我有一些不实现某个界面但在结构上符合该界面的类。
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做到这一点,但我从来没有用过它,乍一看看起来并不容易。
是否有更简单的方法,或者是否有一个库已经实现了这个?
答案 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());