在 .NET 4.0 (C#) 中动态实现接口
Posted
技术标签:
【中文标题】在 .NET 4.0 (C#) 中动态实现接口【英文标题】:Dynamically implementing an interface in .NET 4.0 (C#) 【发布时间】:2011-02-27 19:39:21 【问题描述】:借助 .NET 4.0 中的新动态功能,似乎应该可以动态实现接口,例如给定:
public interface IFoo
string Bar(int baz);
public class Foo : IFoo
public string Bar(int baz) return baz.ToString();
public class Proxy : IDynamicMetaObjectProvider
private readonly object target;
public Proxy(object target) this.target = target;
// something clever goes here
那么我希望有一些方法可以让写作成为可能:
dynamic proxy = new Proxy(new Foo());
IFoo fooProxy = (IFoo)proxy; // because the target object implements it
string bar = fooProxy.Bar(123); // delegates through to the target implementation
但是,到目前为止,我不确定用什么替换 // something clever goes here
。
所以,我的问题是:
这实际上可能与动态运行时有关吗?看起来动态实现方法和属性之类的东西相当容易,但我还没有找到任何关于动态实现接口和转换它们的文档。
假设这是可能的,它可能有多困难? (你可以假设我是一个体面的程序员,在反射等方面有丰富的经验,但对动态框架不熟悉。)
是否有任何资源可以帮助我指出实施此类事情的正确方向?或者甚至可以作为起点的此类事情已经完成的示例?
【问题讨论】:
实现接口方法的代码从哪里来? 【参考方案1】:开源框架Impromptu-Interface 就是为此而设计的。它生成一个缓存的轻量级 具有静态接口的代理,并使用 dlr 将调用转发到原始对象。
using ImpromptuInterface;
public interface ISimpeleClassProps
string Prop1 get;
long Prop2 get;
Guid Prop3 get;
-
dynamic tOriginal= new ExpandoObject();
tOriginal.Prop1 = "Test";
tOriginal.Prop2 = 42L;
tOriginal.Prop3 = Guid.NewGuid();
ISimpeleClassProps tActsLike = Impromptu.ActLike(tOriginal);
【讨论】:
多么棒的框架。我发现自己经常使用它。【参考方案2】:据我所知,如果没有人工干预,就不可能编写或生成将接口成员转发到包装实例的代码。如果您希望看到 Microsoft 为此类事情提供支持,您可能需要考虑在 https://connect.microsoft.com/VisualStudio/feedback/details/526307/add-automatic-generation-of-interface-implementation-via-implementing-member 投票 .
【讨论】:
我认为反馈已移至visualstudio.uservoice.com/forums/121579-visual-studio-ide/…,但已关闭。 C# 功能请求现在应该转到 github.com/dotnet/csharplang【参考方案3】:我想我写了一个库来做你想做的事……它被称为 DynamicWrapper(在 CodePlex 上),它会自动包装一个类,因此它实现了一个接口。 Is this what you want?
【讨论】:
这个想法是一样的,但是看起来你的包装器使用反射发射?这也是我们目前用来执行此操作的方法,但我很好奇它是否可以使用动态框架完成,而不必使用反射发射。 代码示例,所以它不是“仅链接”的答案?【参考方案4】:显式转换、as
和 is
失败,因为类型比较会针对您的代理基类,但隐式转换可以触发 DynamicObject.TryConvert,这样您就可以返回内部对象来代替动态对象.
- TryConvert MSDN Documentation
虽然下面的代码有效,但这本身不是接口委托,只是内部状态的暴露。听起来您可能正在寻找类似拦截模式的东西,例如 Brian 的 DynamicWrapper。
dynamic wrapper = new Proxy(new Foo());
IFoo foo = wrapper;
foo.Bar();
class Proxy : DynamicObject
...
public override bool TryConvert(ConvertBinder binder, out object result)
Type bindingType = binder.Type;
if (bindingType.IsInstanceOfType(target))
result = target;
return true;
result = null;
return false;
【讨论】:
+1,但我没有遵循:为什么显式转换失败?这很奇怪,因为ConvertBinder
有 Explicit
属性可以查询。
Jordão 似乎与在生成的 IL 中生成 Binder.Convert 调用的隐式转换语法不同,“is”和“as”语法省略了转换测试。即在 q) 示例中,显然 type Foo != type Proxy.【参考方案5】:
补充来自@jbtule 的答案,我创建了我的 CustomActivator,它能够在运行时创建一个动态对象并使其实现所需的接口。我也使用Impromptu-Interface framework 来实现这一点。
调用很简单:
CustomActivator.CreateInstance<MyInterface>();
我把它放在github。
【讨论】:
以上是关于在 .NET 4.0 (C#) 中动态实现接口的主要内容,如果未能解决你的问题,请参考以下文章
在 C# 中实例化实现 .NET 接口的 IronPython 类型