0

考虑在具有类层次结构的 .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)它时,随后调用FooA合适的派生类。

现在,我想Foo()相同的代码覆盖,所以派生的所有类A都继承这个自定义实现。

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

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 

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

4

1 回答 1

2

是的。它被称为代理,它是实体框架使用的一种技术。有几种方法可以实现这一点,但 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();
        }
    }
}
于 2013-10-29T03:00:00.187 回答