Annie
Annie

Reputation: 3190

Reflection to override virtual function in base class

Consider a namespace defined in .NET framework with a class hierarchy.

namespace OfficialDotnetNS
{

    namespace officialNS.Bases
    {
        public class BaseOfA : IFakeA, IFakeB 
        {
            protected void Driver(Stream stream){ this.DriveFoo(stream); };
            protected internal virtual void DriveFoo(Stream stream);
        }
    }

    public abstract class A : officialNS.Bases.BaseofA
    {
        protected internal override void DriveFoo(Stream stream){ this.Foo(stream); };

        protected virtual void Foo(String stream);
    }

    public class B : A {}

    public class C : A {}

    public class D : A {}

    // and 50+ similar classes derived from A
}

I have a BaseofA object and when I call Driver(stream) it subsequently calls Foo of A and that of suitable derived class.

Now, I want to override Foo() with same code, so all classes derived from A inherit this custom implementation.

One way is to write custom wrapper for each class:

public class CustomB : B
{
    protected override void Foo(Stream stream)
    {
        stream.Position = 12;
        base.Foo(stream);
    }
}

public class CustomC : C
{
    protected override void Foo(Stream stream)
    {
        stream.Position = 12;
        base.Foo(stream);
    }
}

public class CustomD : D 
{
    protected override void Foo(Stream stream)
    {
        stream.Position = 12;
        base.Foo(stream);
    }
}

//.. for all 50+ classes 

Can we do this using reflection or some other technique without repeating code?

Upvotes: 0

Views: 866

Answers (1)

spender
spender

Reputation: 120518

Yes. It's called proxying and it's a technique used by entity framework. There are several ways of achieving this, but IMO the best is the CastleProject DynamicProxy.

For instance (a simplified case, but I think this does what you want):

void Main()
{
    var pg = new Castle.DynamicProxy.ProxyGenerator();
    var typeA = typeof(A);
    var interceptor = 
        new FooInterceptor(
            str => Console.WriteLine("intercepted {0}", str));
    IEnumerable<A> objs = Assembly
        .GetExecutingAssembly()
        .GetTypes()
        .Where(t => t.IsSubclassOf(typeA))
        .Select(t => (A)(pg.CreateClassProxy(t, interceptor)));

    foreach(A a in objs)
    {
        a.CallFoo("hello world");
    }
}

public class A
{
    public void CallFoo(string someString){
        Foo(someString);
    }
    protected virtual void Foo(string someString)
    {
        Console.WriteLine("base Foo {0}", someString);
    }
}
public class B : A {}

public class C : A {}

public class D : A {}

public class FooInterceptor : IInterceptor
{
    Action<string> interceptorDelegate;
    public Interceptor(Action<string> interceptorDelegate)
    {
        this.interceptorDelegate = interceptorDelegate;
    }
    public void Intercept(IInvocation invocation)
    {
        var isFooCall = invocation.Method.Name == "Foo";
        if(isFooCall)
        {
            interceptorDelegate
                .Invoke((string)(invocation.Arguments[0]));
        }
        else
        {
            invocation.Proceed();
        }
    }
}

Upvotes: 2

Related Questions