回答
这真的取决于你所说的“mixin” - 每个人似乎都有一个略有不同的想法。那种混入的我倒是喜欢向看到(但不可用在C#中)正在实施,通过构图简单:
public class Mixin : ISomeInterface
{
private SomeImplementation impl implements ISomeInterface;
public void OneMethod()
{
// Specialise just this method
}
}
,编译器将实现ISomeInterface只是每个成员代理到“ impl“,除非班上另有实施。
无的,这是可能的此刻虽然:)
LinFu和Castle's DynamicProxy实施混入。 COP(复合面向编程)可以被认为是从mixin中构建一个完整的范例。 This post from Anders Noras有很有用的信息和链接。
编辑:这是所有可能与C#2.0,没有扩展方法
有一个开源框架,使您能够通过C#实现的混入。看看http://remix.codeplex.com/。
这个框架很容易实现mixin。只需查看样本和页面上的“附加信息”链接即可。
我通常采用以下模式:
public interface IColor
{
byte Red {get;}
byte Green {get;}
byte Blue {get;}
}
public static class ColorExtensions
{
public static byte Luminance(this IColor c)
{
return (byte)(c.Red*0.3 + c.Green*0.59+ c.Blue*0.11);
}
}
我有相同的源文件/命名空间中的两个定义。 这种方式使用接口时(使用''),扩展总是可用的。
这会给你一个受限mixin,如CMS的第一个链接中所述。
限制:
- 没有数据字段
- 没有属性(你必须调用myColor.Luminance()带括号的,extension properties人?)
它仍足以让许多的情况。
这将是很好,如果他们(MS)可以添加一些编译器魔法自动生成的扩展类:
public interface IColor
{
byte Red {get;}
byte Green {get;}
byte Blue {get;}
// compiler generates anonymous extension class
public static byte Luminance(this IColor c)
{
return (byte)(c.Red*0.3 + c.Green*0.59+ c.Blue*0.11);
}
}
尽管乔恩提出的编译器把戏会更好。
你也可以增加扩展方法的方式来合并状态,这与WPF的附加属性无异。
这是一个最小样板的例子。请注意,目标类不需要修改,包括添加接口,除非需要多态处理目标类 - 在这种情况下,最终会得到与实际多重继承非常接近的内容。
// Mixin class: mixin infrastructure and mixin component definitions
public static class Mixin
{
// =====================================
// ComponentFoo: Sample mixin component
// =====================================
// ComponentFooState: ComponentFoo contents
class ComponentFooState
{
public ComponentFooState() {
// initialize as you like
this.Name = "default name";
}
public string Name { get; set; }
}
// ComponentFoo methods
// if you like, replace T with some interface
// implemented by your target class(es)
public static void
SetName<T>(this T obj, string name) {
var state = GetState(component_foo_states, obj);
// do something with "obj" and "state"
// for example:
state.Name = name + " the " + obj.GetType();
}
public static string
GetName<T>(this T obj) {
var state = GetState(component_foo_states, obj);
return state.Name;
}
// =====================================
// boilerplate
// =====================================
// instances of ComponentFoo's state container class,
// indexed by target object
static readonly Dictionary<object, ComponentFooState>
component_foo_states = new Dictionary<object, ComponentFooState>();
// get a target class object's associated state
// note lazy instantiation
static TState
GetState<TState>(Dictionary<object, TState> dict, object obj)
where TState : new() {
TState ret;
if(!dict.TryGet(obj, out ret))
dict[obj] = ret = new TState();
return ret;
}
}
用法:
var some_obj = new SomeClass();
some_obj.SetName("Johny");
Console.WriteLine(some_obj.GetName()); // "Johny the SomeClass"
注意,它也可以使用空的情况下,因为扩展方法做自然。
您可能还会考虑使用WeakDictionary实现来避免由集合持有将目标类引用作为键所导致的内存泄漏。
我需要类似的东西,所以我想出了以下使用Reflection.Emit。在下面的代码中,动态生成了一个新类型,它有一个类型为'mixin'的私有成员。所有对'mixin'接口方法的调用都被转发给这个私有成员。定义了一个参数构造函数,该构造函数接受一个实现“mixin”接口的实例。基本上,它是等于写入下述代码对于给定的具体类型T和接口I:
class Z : T, I
{
I impl;
public Z(I impl)
{
this.impl = impl;
}
// Implement all methods of I by proxying them through this.impl
// as follows:
//
// I.Foo()
// {
// return this.impl.Foo();
// }
}
这是类:
public class MixinGenerator
{
public static Type CreateMixin(Type @base, Type mixin)
{
// Mixin must be an interface
if (!mixin.IsInterface)
throw new ArgumentException("mixin not an interface");
TypeBuilder typeBuilder = DefineType(@base, new Type[]{mixin});
FieldBuilder fb = typeBuilder.DefineField("impl", mixin, FieldAttributes.Private);
DefineConstructor(typeBuilder, fb);
DefineInterfaceMethods(typeBuilder, mixin, fb);
Type t = typeBuilder.CreateType();
return t;
}
static AssemblyBuilder assemblyBuilder;
private static TypeBuilder DefineType(Type @base, Type [] interfaces)
{
assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.RunAndSave);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(Guid.NewGuid().ToString());
TypeBuilder b = moduleBuilder.DefineType(Guid.NewGuid().ToString(),
@base.Attributes,
@base,
interfaces);
return b;
}
private static void DefineConstructor(TypeBuilder typeBuilder, FieldBuilder fieldBuilder)
{
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
MethodAttributes.Public, CallingConventions.Standard, new Type[] { fieldBuilder.FieldType });
ILGenerator il = ctor.GetILGenerator();
// Call base constructor
ConstructorInfo baseCtorInfo = typeBuilder.BaseType.GetConstructor(new Type[]{});
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, typeBuilder.BaseType.GetConstructor(new Type[0]));
// Store type parameter in private field
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Stfld, fieldBuilder);
il.Emit(OpCodes.Ret);
}
private static void DefineInterfaceMethods(TypeBuilder typeBuilder, Type mixin, FieldInfo instanceField)
{
MethodInfo[] methods = mixin.GetMethods();
foreach (MethodInfo method in methods)
{
MethodInfo fwdMethod = instanceField.FieldType.GetMethod(method.Name,
method.GetParameters().Select((pi) => { return pi.ParameterType; }).ToArray<Type>());
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
fwdMethod.Name,
// Could not call absract method, so remove flag
fwdMethod.Attributes & (~MethodAttributes.Abstract),
fwdMethod.ReturnType,
fwdMethod.GetParameters().Select(p => p.ParameterType).ToArray());
methodBuilder.SetReturnType(method.ReturnType);
typeBuilder.DefineMethodOverride(methodBuilder, method);
// Emit method body
ILGenerator il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, instanceField);
// Call with same parameters
for (int i = 0; i < method.GetParameters().Length; i++)
{
il.Emit(OpCodes.Ldarg, i + 1);
}
il.Emit(OpCodes.Call, fwdMethod);
il.Emit(OpCodes.Ret);
}
}
}
这是用法:
public interface ISum
{
int Sum(int x, int y);
}
public class SumImpl : ISum
{
public int Sum(int x, int y)
{
return x + y;
}
}
public class Multiply
{
public int Mul(int x, int y)
{
return x * y;
}
}
// Generate a type that does multiply and sum
Type newType = MixinGenerator.CreateMixin(typeof(Multiply), typeof(ISum));
object instance = Activator.CreateInstance(newType, new object[] { new SumImpl() });
int res = ((Multiply)instance).Mul(2, 4);
Console.WriteLine(res);
res = ((ISum)instance).Sum(1, 4);
Console.WriteLine(res);
如果你有一个可以存储数据的基类,你可以强制编译器安全并使用标记接口。 这或多或少是从接受的答案中提出的“Mixin in C#3.0”。
public static class ModelBaseMixins
{
public interface IHasStuff{ }
public static void AddStuff<TObjectBase>(this TObjectBase objectBase, Stuff stuff) where TObjectBase: ObjectBase, IHasStuff
{
var stuffStore = objectBase.Get<IList<Stuff>>("stuffStore");
stuffStore.Add(stuff);
}
}
的ObjectBase:
public abstract class ObjectBase
{
protected ModelBase()
{
_objects = new Dictionary<string, object>();
}
private readonly Dictionary<string, object> _objects;
internal void Add<T>(T thing, string name)
{
_objects[name] = thing;
}
internal T Get<T>(string name)
{
T thing = null;
_objects.TryGetValue(name, out thing);
return (T) thing;
}
所以,如果你有一个类可以继承“ObjectBase”,并与IHasStuff装点您可以添加某些材料现在
这是一个混合的实现我”我刚刚想出来。我可能会用它a library of mine。
它可能已经完成之前,某处。
这是所有静态类型,没有字典或东西。它需要每种类型的额外代码的一点点,你不需要每个实例的任何存储。另一方面,如果您愿意,它还可以灵活地改变即时混音实现。没有后期构建,预构建和中期构建工具。
它有一些限制,但它确实允许重写等内容。
我们从定义标记接口开始。稍后可能会添加一些内容:
public interface Mixin {}
此接口由mixins实现。 Mixins是常规类。类型不直接继承或实现mixin。他们只是使用接口公开一个mixin的实例:
public interface HasMixins {}
public interface Has<TMixin> : HasMixins
where TMixin : Mixin {
TMixin Mixin { get; }
}
实现此接口意味着支持mixin。明确实施它很重要,因为我们将为每种类型提供几种这样的产品。
现在使用扩展方法的一个小技巧。我们定义:
public static class MixinUtils {
public static TMixin Mixout<TMixin>(this Has<TMixin> what)
where TMixin : Mixin {
return what.Mixin;
}
}
Mixout
暴露了适当类型的mixin。现在,测试了这一点,让我们定义:
public abstract class Mixin1 : Mixin {}
public abstract class Mixin2 : Mixin {}
public abstract class Mixin3 : Mixin {}
public class Test : Has<Mixin1>, Has<Mixin2> {
private class Mixin1Impl : Mixin1 {
public static readonly Mixin1Impl Instance = new Mixin1Impl();
}
private class Mixin2Impl : Mixin2 {
public static readonly Mixin2Impl Instance = new Mixin2Impl();
}
Mixin1 Has<Mixin1>.Mixin => Mixin1Impl.Instance;
Mixin2 Has<Mixin2>.Mixin => Mixin2Impl.Instance;
}
static class TestThis {
public static void run() {
var t = new Test();
var a = t.Mixout<Mixin1>();
var b = t.Mixout<Mixin2>();
}
}
而可笑的(虽然现在回想起来,这有一定道理),智能感知不检测的扩展方法Mixout
适用于Test
,但编译器接受它,只要Test
实际上有mixin。如果你尝试,
t.Mixout<Mixin3>();
它给你一个编译错误。
你可以去有点花哨,并定义以下方法太:
[Obsolete("The object does not have this mixin.", true)]
public static TSome Mixout<TSome>(this HasMixins something) where TSome : Mixin {
return default(TSome);
}
这样做是什么,一个)显示一个名为智能感知Mixout
方法,提醒你它的存在,和b)提供一个更具描述性的错误信息(由Obsolete
属性生成)。
- 1. 您是否可以在实现它的类中重新定义mixin的方法
- 2. 你可以测试mixin是否存在?
- 3. 是否可以在Phonegap中实现Tesseract?
- 4. 是否可以在ListView中实现ItemTemplate?
- 5. 是否可以在Objective-C中动态实现协议?
- 6. 是否可以实现[]我自己并在C#中使用它?
- 7. 是否可以在C#中实现作用域锁定?
- 8. 是否有可能实现在C#
- 9. 是否可以在C++/CLR中实现在C#中声明的抽象类?
- 10. 是否可以从C++头部构建Objective-C++实现?
- 11. 是否可以在Erlang中实现组件实体系统?
- 12. 是否可以在Windows中实现/运行Java实时程序?
- 13. 这是一个mixin,可以在C++中完成吗?
- 14. 是否可以使用FQL实现friends.getMutualFriends?
- 15. 是否可以实现自己的IASKSettingsReader?
- 16. 是否可以实现__super宏?
- 17. 是否可以用css实现斜边?
- 18. Can Services是否可以实现SensorEventListener
- 19. 是否有可能在C中实现temeplatization,因为它可能在C++中
- 20. 是否可以用C11的_Generic实现GNU C的typeof(x)?
- 21. C编译器是否可以实现“不合理”的右移?
- 22. 如何在Flask中实现MIXIN?
- 23. 是否可以从mixin函数参数中混入?
- 24. 是否可以在C#中使用接口实现动态多态性.net
- 25. 是否可以在Objective-C中实现Haversine公式并从SQLite调用它?
- 26. 是否可以在C#5.0中使用异步实现阴阳谜题?
- 27. 是否可以在F#中实现IDbSet <T>接口?
- 28. 是否可以使用`eval`在Lisp中实现`apply`?
- 29. 是否可以在iOS版本的LIBGDX中实现IAP?
- 30. 是否可以在pyspark中使用apache-ignite rdd实现?
很酷的技术......我一定会为这项技术投票。 – 2010-02-10 08:46:20
安德斯请将此添加到C#5! – Schneider 2010-08-26 05:51:19
我觉得很烦人的是,C++专家发表类似于“更喜欢组合继承”的语句,但语言(C++或C#)为“正确的事情”提供了宝贵的帮助。 – 2010-09-27 14:10:05