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

时间:2009-12-17 08:23:08

标签: c# wrapper

我有一些实现某个界面但在结构上符合该界面的类。

interface IFoo {
    void method();
}

class Bar {  // does not implement IFoo
   public void method() {...}
}

现在,我可以编写一个包装器,围绕那些只是委托给包装类

的类
class BarWrapper : IFoo {
   Bar bar = new Bar();
   public void method()
   {
      bar.method();
   }
}

但这是一项繁琐的工作。那些包装类可以自动生成吗?类似的东西:

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

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

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

8 个答案:

答案 0 :(得分:8)

你想要完成的任务,被称为鸭子打字。 有一些专用的库可以让你这样做,虽然我还没有使用它们。

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

如果出于某种原因,基于拦截器的方法对您来说是不可接受的,动态代理不支持开箱即用(但是),但是如果您使用的是2.2版beta,那么在强大的情况下提供它是相当容易的。通过提供自己的代理类型构建器(请查看mixins的实现方式)来键入方式(不使用拦截器)。

答案 1 :(得分:6)

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

用法示例(取自David Meyer's site):

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);
    }
}

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

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);

答案 2 :(得分:3)

您可以创建一个新类

class SubBar : IFoo, Bar {
}

并实例化(假设 Bar 真的有鸭子型,即确切的 IFoo 方法)。

答案 3 :(得分:2)

你可能想看看Castle Project的DynamicProxy。这就是Rhino.Mocks用于其类型代理的内容。

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

答案 4 :(得分:1)

请查看Introducing “The C# Ducktaper” – Bridging the dynamic world with the static world,因为此博客文章准确描述了您的需求。

答案 5 :(得分:0)

如果您愿意使用.NET 4,解决方案可能是将包装类定义为DynamicObject,并通过使用反射将对动态方法的调用转换为对包装类的调用(I'我不确定这实际上是否会减少工作量;还要考虑与反射使用相关的可能的性能问题。

答案 6 :(得分:0)

虽然我自己没有使用它们,但我认为Visual Studio中的T4模板可用于生成动态类型link text的代码。

答案 7 :(得分:0)

这是使用泛型的略微不同的方法。这需要更多的工作思路。您需要为每个接口实现一个包装器,并使用反射调用所有方法。

class FooWrapper<T> : IFoo
{
   private T obj;

   public FooWrapper(T obj)
   {
      this.obj = obj;
   }

   public void method()
   {
      // call method with reflection
      // obj.method();
   }
}

IFoo foo = new FooWrapper(new Bar());