在 .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】:

显式转换、asis 失败,因为类型比较会针对您的代理基类,但隐式转换可以触发 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,但我没有遵循:为什么显式转换失败?这很奇怪,因为 ConvertBinderExplicit 属性可以查询。 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 类型

C# 等效于 VB.NET 接口实现

.Net在C#中判断某个类是否实现了某个接口

这是引用包含泛型的 C# 接口的 VB.NET 实现的 FxCop 错误吗?

C#动态创建接口的实现实例对象

.Net C# 接口,了解只需3分钟