2015-01-05 2 views
1

특정 유형의 메서드 (예 : 제네릭 형식의 메서드)에서 필드 또는 메서드 참조가 FieldDefinition이 아닌 FieldReference 형식이 될 것으로 나타났습니다. 필드 또는 메서드)가 동일한 유형의 동일한 모듈에 있습니다. 이 FieldReference에서 어떻게 FieldDefinition을 얻을 수 있습니까?Mono.Cecil의 참조에서 멤버 정의 가져 오기

나는 module.Importmodule.MetadataResolver.Resolve을 시도했지만 둘 다 작동하지 않습니다.

후속은 this까지이지만,보다 일반적인 질문입니다.

편집 :

간단한 제네릭 클래스가 :

public class HelperClass<T> 
{ 
    private int _someInt; 

    void SomeMethod(int i) 
    { 
     _someInt = i; 
    } 
} 

SomeMethod의 몸이 포함

... 
IL_0008: ldarg.0 
IL_0009: ldarg.1 
IL_000a: stfdl System.Int32 HelperClass`1<T>::_someInt 
.... 

IL_000a 오피 코드의 피연산자 후, 일반적으로 FieldDefinition 있어야하는데 그것은 모두 동일한 모듈에 있습니다. 하지만 HelperClass이 제네릭이기 때문에 피연산자는 FieldReference으로 해결되지 않을 것입니다. 실제로는 전체 이름을 비교하여 실제로 FieldDefinition을 찾을 수 있습니다.

이 경우 큰 문제는 아니지만 참조가 다른 제네릭 형식의 다른 구성원 인 경우 모든 형식을 열거하는 것보다 더 좋은 방법으로 해당 형식을 찾을 수 있습니다. 정의.

편집 : .Resolve() 수익률이 FieldDefinition을 반환하는 대신 null로 할 때 HelperClass<>AssemblyDefinition.ReadAssembly에 의해 런타임에로드되는 모듈에서입니다

, 즉이다.

UPDATE : 그것은 내가 제네릭 형식의 필드 이름을 변경하고 있습니다 때문에, 참조가 파괴되고 Resolve()가 null 반환 밝혀졌다

. 여전히 this one에 대한 적절한 해결책을 찾으십시오.

+0

참조에서 Resolve()를 호출하는 것이 작동하지 않습니까? (즉,'var myFieldDefinition = myFieldReference.Resolve();') – rileywhite

+0

@rileywhite 아니, null을 반환합니다. 처음에는 정의가되어야한다고 생각했지만 제네릭 타입 멤버에 대한 참조는 Cecil에서 다르게 처리됩니다. – mrahhal

+0

보고있는 것을 재현하는 코드를 게시 할 수 있습니까? – rileywhite

답변

1

업데이트 :

나는 다른 솔루션에서 다른 프로젝트로 유형을 분리하는 코드를 변경했습니다. 불행히도 여전히 문제를 재현 할 수는 없지만 도움이 될만한지 계속 시도하려고합니다.

다음 코드를 사용하여 형식 참조를 확인할 수 있습니다. 재생산에 대한 자세한 내용을 제공 할 수 있다면 다음과 같이 다른 균열을 기꺼이 받아 들일 수 있습니다.

이것은 TargetLibrary.dll이라는 어셈블리의 유일한 유형입니다. 나는 그것을 자체 솔루션으로 컴파일하고 어셈블리를 C:\Temp에 복사했습니다.

public class HelperClass<T> 
{ 
    private int _someInt; 

    void SomeMethod(int i) 
    { 
     _someInt = i; 
    } 
} 

이 코드는 다른 어셈블리에 있으며, 자체 솔루션 내에서 콘솔 exe 파일로 컴파일됩니다.

class Program 
{ 
    static void Main(string[] args) 
    { 
     var module = AssemblyDefinition.ReadAssembly(@"C:\Temp\TargetLibrary.dll").MainModule; 

     Console.WriteLine("For HelperClass<>"); 
     var helperClass = module.Types[1]; 
     var someMethod = helperClass.Methods[0]; 
     var someMethodBody = someMethod.Body; 
     foreach (var instruction in someMethodBody.Instructions) 
     { 
      Console.WriteLine(
       "{0}\t{1}\t{2}", 
       instruction.Offset, 
       instruction.OpCode.Code, 
       instruction.Operand == null ? "<null>" : string.Format("{0}/{1}", instruction.Operand.GetType().FullName, instruction.Operand.ToString())); 

      var fieldReference = instruction.Operand as FieldReference; 
      if (fieldReference != null) 
      { 
       var fieldDefinition = fieldReference.Resolve(); 
       Console.WriteLine(
        "\t\tResolved field reference operand: {0}/{1}", 
        fieldDefinition.GetType().FullName, 
        fieldDefinition.ToString()); 
      } 
     } 
    } 
} 

이렇게하면 다음과 같은 출력이 생성됩니다.

For HelperClass<> 
0  Ldarg_0 <null> 
1  Ldarg_1 <null> 
2  Stfld Mono.Cecil.FieldReference/System.Int32 TargetLibrary.HelperClass`1<T>::_someInt 
       Resolved field reference operand: Mono.Cecil.FieldDefinition/System.Int32 TargetLibrary.HelperClass`1::_someInt 
7  Ret  <null> 
+0

감사합니다. 문제는 참조가 실제로로드 된 모듈에서 오는 것입니다. 런타임에로드 한 모듈에 대해 이야기하고 있습니다. Resolve()가 null을 반환하고 실행중인 어셈블리에서 제네릭 형식을 사용하는 예제가 있는데 다른 하나가 작동하지 않는 이유는 알 수 없습니다. – mrahhal

+0

흠 ... 레퍼런스와 관련된 어셈블리 리졸버가 이미 어셈블리를로드하는 데 리졸버를 사용했기 때문에 어셈블리를 찾는 데 문제가있을 수 있습니다. 몇 분 남았을 때 다시 한 번 가볼께. – rileywhite

+0

내 생각은 정확하게. 더 명확하게하기 위해 MainModule을로드하기 위해'AssemblyDefinition.ReadAssembly'를 사용합니다. 도와 줘서 고맙다. – mrahhal