2013-10-29 2 views
0

.NET Framework에서 정의 된 네임 스페이스가 클래스 계층 구조로 간주됩니다. 기본 클래스에서 가상 함수를 재정의하기위한 리플렉션

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)를 호출 할 때 그것은 이후 AFoo 적합한 파생 클래스의 호출합니다.

지금, 그래서 모든 클래스가 A 상속이 사용자 정의 구현에서 파생 동일한 코드Foo()을 재정의합니다.

한 가지 방법은 각 클래스에 대한 사용자 지정 래퍼를 작성하는 것입니다 :

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 

우리가 사용하는 반사 또는 코드를 반복하지 않고 다른 기술을 할 수 있습니까?

답변

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

당신이 * 모든 * 형제 클래스에 오버라이드 기능을 스탬핑에 초점을 맞추고 DynamicProxy의 특정 기능을 지적 할 수 있습니까? – Annie

+0

@Annie : 설명 할 코드를 추가했습니다. – spender

+0

감사합니다. 거의 모든 것을 지 웁니다. 단지 약간의 호기심. 클래스'BaseOfA'의'DriverFoo'를 호출하려고합니다. 결국'A' 클래스의'Foo'가됩니다. 당신의 예제에서'A'가 부모 클래스를 가지고 있다면 A의 Base로부터 A의 자식을 어떻게 선택하겠습니까? – Annie

관련 문제