您可以創建一個DynamicObject
轉發接收到的目標的列表,在責任風格鏈中的電話(注意,多態分派也是這樣工作 - 從向上最派生類):
public class Composition : DynamicObject {
private List<object> targets = new List<object>();
public Composition(params object[] targets) {
AddTargets(targets);
}
protected void AddTargets(IEnumerable<object> targets) {
this.targets.AddRange(targets);
}
public override bool TryInvokeMember(
InvokeMemberBinder binder, object[] args, out object result) {
foreach (var target in targets) {
var methods = target.GetType().GetMethods();
var targetMethod = methods.FirstOrDefault(m =>
m.Name == binder.Name && ParametersMatch(m, args));
if (targetMethod != null) {
result = targetMethod.Invoke(target, args);
return true;
}
}
return base.TryInvokeMember(binder, args, out result);
}
private bool ParametersMatch(MethodInfo method, object[] args) {
var typesAreTheSame = method.GetParameters().Zip(
args,
(param, arg) => param.GetType() == arg.GetType());
return typesAreTheSame.Count() == args.Length &&
typesAreTheSame.All(_=>_);
}
}
請注意,您還需要爲屬性(TryGetMember
和TrySetMember
),索引器(TryGetIndex
和TrySetIndex
)和運算符(TryBinaryOperation
和TryUnaryOperation
)執行委派。
然後,給出了一組類:
class MyClass {
public void MyClassMethod() {
Console.WriteLine("MyClass::Method");
}
}
class MyOtherClass {
public void MyOtherClassMethod() {
Console.WriteLine("MyOtherClass::Method");
}
}
可以「混合」他們在一起:
dynamic blend = new Composition(new MyClass(), new MyOtherClass());
blend.MyClassMethod();
blend.MyOtherClassMethod();
您還可以擴展動態對象使用類屬性或其他種類的註釋來尋找mixin。例如,給定此註釋接口:
public interface Uses<M> where M : new() { }
你可以有這樣的DynamicObject
:
public class MixinComposition : Composition {
public MixinComposition(object target) :
base(target) {
AddTargets(ResolveMixins(target.GetType()));
}
private IEnumerable<object> ResolveMixins(Type mainType) {
return ResolveMixinTypes(mainType).
Select(m => InstantiateMixin(m));
}
private IEnumerable<Type> ResolveMixinTypes(Type mainType) {
return mainType.GetInterfaces().
Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(Uses<>)).
Select(u => u.GetGenericArguments()[0]);
}
private object InstantiateMixin(Type type) {
return Activator.CreateInstance(type);
}
}
,並創建 「混合」 是這樣的:
class MyMixin {
public void MyMixinMethod() {
Console.WriteLine("MyMixin::Method");
}
}
class MyClass : Uses<MyMixin> {
public void MyClassMethod() {
Console.WriteLine("MyClass::Method");
}
}
...
dynamic blend = new MixinComposition(new MyClass());
blend.MyClassMethod();
blend.MyMixinMethod();
部分類也許?擴展方法? –
通過使用擴展方法,我會寫更多顯式的代碼,將MyClass與我的標記相關的代碼(當然,除了taggable屬性)結合在一起。我想在沒有明確結婚的情況下這樣做。 – ActionJackson