我正在 .NET 中制作可移植类库 (PCL),碰巧在尝试抽象任何行为时,我遇到了一个非常常见的烦恼,即 .NET Framework 对其类型和接口(interface)的占有欲很强强>。发现一个类型没有实现任何接口(interface)是很常见的,或者当它实现时,接口(interface)是内部的。
当现有类型具有兼容的方法(相同的名称和签名)时,这很容易:我一直在像这样使用 ImpromptuInterface:
nakedInstanceTheDoesNotImplementAnything.ActAs<MyBeautifulInterface>();
我得到了我想要的。透明且方便。
但是,有些方法略有不同怎么办?
- 不同的名字
- 调用点不同:一个是属性getter,一个是方法
- 一些不同的方法,但只需稍作修改即可轻松适应它们。
通常,建议使用纯 OOP 方法,并告知我们创建和适配器。 但是当您必须适应复杂的类型层次结构时,这可能非常乏味和复杂,当您拥有 UIElement、Control、FrameworkElement 等庞大的类时更是如此……
问题是:我能否使 ImpromptuInterface 克服类型中的这些变化以动态创建适配器?
最佳答案
所以 ImpromtuInterface
使用 DLR,基本上当您调用 ActLike() 时,它会发出并缓存该接口(interface)的代理,并将其包装在您的对象周围。
public class Proxy:IMyInterface {
dynamic target;
public int Foo(){
return (int)target.Foo()
}
}
因为它是一个动态调用,如果它是并且 IDynamicMetaObjectProvider 最流行的自定义方法是 System.Dynamic.DynamicObject
,那么您实际上并没有在您的目标上使用该方法.
public class RoughDynamicAdapter:DynamicObject{
public override bool TryInvokeMember(InvokeMemberBinder binder,
Object[] args,
out Object result){
if(binder.Name == "Foo"){
result = /* do your own logic */
return true;
}
result = null;
return false;
}
}
但这需要大量工作,因为您必须像处理修改后的调用一样处理未修改的调用。
有几个预制件DynamicObject
在ImpromptuInterface
我已经搬到了一个单独的图书馆 Dynamitey .
特别是一个,BaseForwarder
听起来像您想要的,因为无需处理所有逻辑,将消息转发到目标对象已作为基本功能实现。
public class DynamicAdapter:Dynamitey.DynamicObjects.BaseForwarder {
public DynamicAdapter(object target):base(target){
}
public override bool TryInvokeMember(InvokeMemberBinder binder,
Object[] args,
out Object result){
var newName = binder.Name;
if(newName == "Foo"){
result = Dynamic.InvokeMember(CallTarget, "Bar", args)
return true;
}
//else pass them method on as it was called
return base.TryInvokeMember(binder, args, out result)
}
}
然后使用它将是 new DynamicAdapter(myObject).ActLike<IMyInterface>()
关于c# - 当实现略有不同时如何使用 DuckTyping?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21613651/