2010-12-04 5 views
5

는 다음과 같은 사소한 코드를 살펴 보자 :DynamicMethod를 사용하는 런타임 코드 삽입?

using System; 
class Test 
{ 
    delegate int FooDelegate(int i); 
    FooDelegate Foo = FooImplementation; 
    static int FooImplementation(int i) 
    { 
     return i + 1; 
    } 

    public static void Main() 
    { 
     Foo(1); 
    } 
} 

내가 뭘하고 싶은 것은 동등한 것 푸 대표로 일부 디버깅 코드를 삽입입니다 :

FooDelegate Foo = delegate(int i) 
{ 
    try 
    { 
     DebugPrologue(); 
     return FooImplementation(i); 
    } 
    finally 
    { 
     DebugEpilogue(); 
    } 
}; 

트위스트 내가해야한다는 것입니다 런타임에서이 작업을 수행 할 수 있으므로 컴파일 타임 및 후 처리 방법은 문제가되지 않습니다.

필자의 초기 접근 방식은 Foo 대리자에게 프롤로그 및 에필로그 메서드를 추가하기 위해 Delegate.Combine()을 사용했습니다. 슬프게도, 반환 값을 변경하지 않으므로 작동하지 않습니다.

현재 나의 생각은 System.Reflection.Emit 및 DynamicMethod를 잠재적 인 솔루션으로 사용하는 것입니다. 필자가 말할 수있는 한, FooImplementation을위한 MethodInfo를 얻고, MethodBody를 얻고, DynamicMethod로 변환하고 try-finally 블록을 삽입해야합니다.

불행히도, 나는 어떻게 이런 일을하는지 전혀 모릅니다. 핸드를 기꺼이 빌려주는 사람은 누구입니까? 아니면 다른 아이디어가 있습니까?

편집 : 여기의 유스 케이스는 OpenGL 바인딩 (http://www.opentk.com)을 디버깅하는 것입니다. 우리는 격렬하게 다른 매개 변수로 2226 방법을 주입해야하므로 일반적인 접근이 필요합니다.

당신이해야 할 노력하고 있지만, 단순히 Foo 필드에서 지적 년대 FooImplementation를 리디렉션 않다면 어떤

답변

0

내가 마침내 끝낸 것은 Mono.Cecil을 사용하여 내 자신의 다시 쓰기 솔루션을 구현하는 것이 었습니다.간단하고 빠르며 잘 작동합니다. 불행히도 이것은 빌드 후 이벤트로 수행되어야하므로 실제로는 런타임 코드 주입이 아닙니다.

0

참고하십시오 당신은 간단하게 수행 할 수 있습니다를 주입가 없습니다 물론

class Test 
{ 
    delegate int FooDelegate(int i); 
    static FooDelegate Foo = FooImplementation; 

    static int FooImplementation(int i) 
    { 
     return i + 1; 
    } 

    public static void Main() 
    { 
     Inject(); 
     Foo(1); 
    } 


    public static void Inject() 
    { 
     var oldImpl = Foo; 

     Foo = i => 
      { 
       try 
       { 
        BeginDebug(); 
        return oldImpl(i); 
       } 
       finally 
       { 
        EndDebug(); 
       } 
      }; 
    } 

    public static void BeginDebug() 
    { 
     Console.WriteLine("Begin Foo"); 
    } 

    public static void EndDebug() 
    { 
     Console.WriteLine("End Foo"); 
    } 
} 

같은 클래스에 있어야하지만 필드/속성이 공개적으로 액세스 할 수없는 경우 리플렉션을 사용하여 수행해야합니다. 그래도 그렇게 어렵지는 않습니다.

+0

이 솔루션은 삽입 할 수있는 많은 방법에 대해 완벽하게 작동합니다. 불행히도,이 특정 경우에 난 격렬하게 다른 매개 변수를 2226 메서드를 주입해야합니다 (이것은 OpenGL 바인딩입니다,이를 반영하기 위해 원래 질문을 업데이트 할 것입니다). –

0

다음과 같은 것을 사용 해본 적이 있습니까? Postsharp? http://www.sharpcrafters.com/postsharp

또는 엔터프라이즈 라이브러리 정책 주입? http://msdn.microsoft.com/en-us/library/ff650672.aspx

심지어 Mono.Cecil? http://www.mono-project.com/Cecil

+0

Mono.Cecil 및 postsharp는 컴파일 타임에 실행되며 여기서는 작동하지 않습니다 (런타임시 비활성화/활성화 할 수 있어야합니다). 전에 엔터프라이즈 라이브러리를 선택하지 않았습니다. 감사합니다. –

0

TypeMock 또한 어쩌면 문제에 대한 가능한 해결책 : http://www.typemock.com/

당신은 또한 RealProxy 클래스 (http://msdn.microsoft.com/en-us/library/system.runtime를 사용할 수 있습니다. remoting.proxies.realproxy.aspx) 런타임에 자신의 프록시를 생성합니다. 먼저 주입 된 코드를 호출 한 다음 실제 메소드를 호출합니다.

3

표현식을 사용할 수 있습니다.

var param = Expression.Parameter(typeof(int), "i"); 

Foo = Expression.Lambda(
     Expression.TryFinally(
      Expression.Block(
       <expression for DebugPrologue>, 
       Expression.Invoke(<expression for FooImplementation>, param)), 
      <expression for DebugEpilogue>), 
     param) 
     .Compile(); 

이렇게하면 런타임에 프롤로그와 에필로그에 대한 표현을 구축 할 수 있습니다.

+0

감사합니다. 매우 간단하고 우아합니다. 이 솔루션을 테스트하겠습니다. 제대로 작동해야합니다. –

+0

FYI, 컴파일 된 표현식에서는 DynamicMethod를 사용합니다. –

0

을 codeplex에서 관리 코드 (C# 또는 VB.NET)에 쉽게 삽입 할 수 있습니다.