views:

278

answers:

2

When you have a class car that implements IVehicle and you want to wrap it in a decorator that forwards all calls to car and counts them, how would you do it?

In Ruby I could just build a decorator without any methods and use method_missing to forward all calls to the car object.

In Java I could build a Proxy object that runs all code through one method and forwards it afterwards.

Is there any similiar thing i can do in C#?


update:

based on the answeres and what i´ve read about System.Reflection.Emit it should be possible to write a method similiar to this:

Type proxyBuilder(Type someType, delagate functionToBeApplied, Object forward)

where type implements all interface of someType, executes functionToBeApplied and then forwards the method call to object while returning its return.

Is there some lib that does just that or would i have to write my own?

+1  A: 

Unfortunately, there is no mixin support in C#. So you'd need to implement all methods, or use some heavy-duty reflection.emit to do it. The other alternative is an (optional) proxy /decorator base class...

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
}

then

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

Noting that use of the FooBase is strictly optional; any IFoo is allowed.

Marc Gravell
+4  A: 

For proxying you could look into "RealProxy" if you want to use standard types, it's a little bit of a hassle to use though (and it requires your classes inherit from 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);
    }
}

Alternatively you could get "DynamicProxy" from Castle.. It works a bit better in my experience..

If you use one of those you won't neccessarily get great performance though, I use them primarily in calls that will likely be slow in the first place.. But you could try it out if you want.

Marc's solution will have better performance.

Sciolist