反映基类中的虚函数

时间:2013-10-29 02:42:31

标签: c# reflection inversion-of-control

考虑在.NET框架中使用类层次结构定义的命名空间。

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
}

我有BaseofA个对象,当我致电Driver(stream)时,它会调用Foo的{​​{1}}和合适的派生类。{/ p>

现在,我想用相同代码覆盖A,因此从Foo()派生的所有类都会继承此自定义实现。

一种方法是为每个类编写自定义包装器:

A

我们可以使用反射或其他技术来做到这一点而不重复代码吗?

1 个答案:

答案 0 :(得分:1)

是。它被称为代理,它是实体框架使用的技术。有几种方法可以实现这一目标,但最好的IMO是CastleProject DynamicProxy

例如(一个简化的案例,但我认为这可以做你想要的):

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