在C#中实现代理或装饰器类的最短方法是什么?

7
当你有一个实现了IVehicle接口的class car,你想要将其包装在一个装饰器中,该装饰器将所有调用转发到car并对其进行计数,你该如何做呢?
在Ruby中,我可以构建一个没有任何方法的装饰器,并使用method_missing将所有调用转发到car对象。
在Java中,我可以构建一个代理对象,通过一个方法运行所有代码,然后将其转发。
在C#中是否有类似的方法可用?
更新:
根据答案和我所读关于System.Reflection.Emit的内容,应该可以编写类似于以下示例的方法:
Type proxyBuilder(Type someType, delagate functionToBeApplied, Object forward)

where type执行someType的所有接口,执行functionToBeApplied并将方法调用转发到对象,同时返回其返回值。

是否有一些库可以做到这一点,还是我需要自己编写?

2个回答

4

如果要使用标准类型进行代理,您可以考虑使用"RealProxy",但是使用起来有些麻烦(并且需要您的类继承自MarshalByRefObject)。

public class TestProxy<T> : RealProxy where T : class
{
    public T Instance { get { return (T)GetTransparentProxy(); } }
    private readonly MarshalByRefObject refObject;
    private readonly string uri;

    public TestProxy() : base(typeof(T))
    {
        refObject = (MarshalByRefObject)Activator.CreateInstance(typeof(T));
        var objRef = RemotingServices.Marshal(refObject);
        uri = objRef.URI;
    }

    // You can find more info on what can be done in here off MSDN.
    public override IMessage Invoke(IMessage message)
    {
        Console.WriteLine("Invoke!");
        message.Properties["__Uri"] = uri;
        return ChannelServices.SyncDispatchMessage(message);
    }
}

或者你可以从Castle获取“DynamicProxy”。在我的经验中,它的效果更好。

如果你使用其中之一,你不一定会得到很好的性能,我主要在可能本来就会很慢的调用中使用它们。但是如果你想尝试一下,也可以。

Marc的解决方案将具有更好的性能。


2

很遗憾,C#中没有mixin支持。因此,您需要实现所有方法,或使用一些重型反射.emit来完成它。另一种选择是使用(可选的)代理/装饰器基类...

abstract class FooBase : IFoo {
   protected FooBase(IFoo next) {this.next = next;}
   private readonly IFoo next;
   public virtual void Bar() { // one of the interface methods
       next.Bar();
   }
   public virtual int Blop() { // one of the interface methods
       return next.Blop();
   }
   // etc
}

那么

class SomeFoo : FooBase {
   public SomeFoo(IFoo next) : base(next) {}
   public override void Bar() {...}
}

请注意,使用FooBase是完全可选的;任何IFoo都可以使用。


请简要解释一下,“使用FooBase是完全可选的”是什么意思?这是否意味着“任何IFoo都是允许的”?分号使我将语句分开阅读,而论据本身足以增加混淆。尽管显而易见的指出:“这只是意味着FooBase可以被任何其他实现了IFoo接口的类替换”,但如果事情如此简单,我会感到失望。我不是对答案感到失望,而是对自己的偏执感到失望。抱歉我的表述有些啰嗦(现在我需要找到一个与之相应的习语)。 - jungle_mole
1
我认为这是令人失望的答案;代码应该只依赖于IFooFooBase只是方便选择实现IFoo的代码。 - Marc Gravell
谢谢!如果您有时间,请回答两个问题:1)这个主题已经6年了,看起来自那以后没有什么改变,解决问题的方法仍然是一样的?(从未想过我会想念C++,但它有->重载)2)我是否理解错误:您是说从抽象类继承是不好的实践?我自己认为它们是带有默认实现的接口,并且它们非常方便。并且可以将SomeFoo实例称为IFoo,显然。(与此同时,微软实现了扩展方法的多态性...) - jungle_mole

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接