自动创建包装器以实现接口

hel*_*ium 16 c# wrapper

我有一些类没有实现某个接口,但在结构上符合该接口.

interface IFoo {
    void method();
}

class Bar {  // does not implement IFoo
   public void method() {...}
}
Run Code Online (Sandbox Code Playgroud)

现在,我可以围绕那些简单地委托给包装类的类编写一个包装器

class BarWrapper : IFoo {
   Bar bar = new Bar();
   public void method()
   {
      bar.method();
   }
}
Run Code Online (Sandbox Code Playgroud)

但那是很多繁琐的工作.那些包装类可以自动生成吗?就像是:

IFoo foo = CreateWrapper<IFoo>(new Bar());

我相信你可以用Reflection.Emit做到这一点,但我从来没有用过它,乍一看它看起来并不容易.

有没有更简单的方法,或者是否有一个库已经实现了这个?

Krz*_*mic 8

你想要完成什么,被称为鸭子打字.有一些专用库可以让你这样做,虽然我没有使用它们中的任何一个.

只需很少的努力(以及一些反思),您就可以使用Castle Dynamic Proxy来执行此操作,使用此处概述的方法.

如果出于某种原因,基于拦截器的方法对你来说是不可接受的,动态代理不支持开箱即用(但是),但是如果你使用2.2版beta,那么以强类型方式提供它是相当容易的(不使用拦截器),提供自己的代理类型构建器(看看如何实现mixins).


Gro*_*roo 6

如果您想要轻松简单的Duck打字支持,您还可以查看:Duck Typing项目.它适用于.Net 2.0及更新版本.

用法示例(摘自David Meyer的网站):

public interface ICanAdd
{
    int Add(int x, int y);
}

// Note that MyAdder does NOT implement ICanAdd, 
// but it does define an Add method like the one in ICanAdd:
public class MyAdder
{
    public int Add(int x, int y)
    {
        return x + y;
    }
}

public class Program
{
    void Main()
    {
        MyAdder myAdder = new MyAdder();

        // Even though ICanAdd is not implemented by MyAdder, 
        // we can duck cast it because it implements all the members:
        ICanAdd adder = DuckTyping.Cast<ICanAdd>(myAdder);

        // Now we can call adder as you would any ICanAdd object.
        // Transparently, this call is being forwarded to myAdder.
        int sum = adder.Add(2, 2);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用扩展方法,您可以将其简化为类似这样的东西(类似于Bart De Smet的语法)

MyAdder myAdder = new MyAdder(); // this doesn't implement the interface
ICanAdd adder = myAdder.AsIf<ICanAdd>(); // but it quacks like a duck
int sum = adder.Add(2, 2);
Run Code Online (Sandbox Code Playgroud)


Jos*_*Fox 5

你可以创建一个新类

class SubBar : IFoo, Bar {
}
Run Code Online (Sandbox Code Playgroud)

并实例化它(假设Bar确实具有 ducktype,即确切的IFoo方法)。


Jon*_*eet 2

您可能想看看 Castle Project 的DynamicProxy。这就是Rhino.Mocks用于其类型代理的方式。

我自己没有使用过它,所以我不知道你需要付出多少努力,但我怀疑这是一个很好的起点。