2015-07-07 1 views
3

У меня есть следующий код, который в основном создает динамическую сборку с двумя типами с одним открытым методом.Как получить правильную ссылку на метод при выполнении команды JMP для метода, который находится в другой сборке

 var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly 
       (new AssemblyName("TestAssembly"), AssemblyBuilderAccess.Run); 
     var module = assembly.DefineDynamicModule("Main"); 
     var type1 = module.DefineType("type1"); 


     var method1 = type1.DefineMethod 
         (
         "Method1", MethodAttributes.Public, typeof(void), null 
        ); 

     var gen = method1.GetILGenerator(); 
     gen.Emit(OpCodes.Ret); 

     var t1 = type1.CreateType(); 

     var createdMethod1 = t1.GetMethod("Method1"); 

     var type2 = module.DefineType("type2"); 

     var method2 = type2.DefineMethod 
         (
         "Method2", MethodAttributes.Public, typeof(void), null 
        ); 


     byte[] ilCodes = new byte[5]; 
     ilCodes[0] = (byte)OpCodes.Jmp.Value; 
     ilCodes[1] = (byte)(createdMethod1.MetadataToken & 0xFF); 
     ilCodes[2] = (byte)(createdMethod1.MetadataToken >> 8 & 0xFF); 
     ilCodes[3] = (byte)(createdMethod1.MetadataToken >> 16 & 0xFF); 
     ilCodes[4] = (byte)(createdMethod1.MetadataToken >> 24 & 0xFF); 

     method2.SetMethodBody(ilCodes, ilCodes.Length, null, null, null); 


     var obj = Activator.CreateInstance(type2.CreateType()); 

     obj.GetType().GetMethod("Method2").Invoke(obj, null); 

Всякий раз, когда я делаю вызов type2.method2() У меня есть инструкции JMP к type1.method1().

Это работает как шарм, оба типа находятся в одной и той же сборке.

Теперь, если я хочу перенаправить на тип, который находится в другой сборке, как я могу получить правильную ссылку на сборку/модуль, чтобы команда JMP преуспела. Если я просто сделаю вот так:

 byte[] ilCodes = new byte[5]; 
     ilCodes[0] = (byte)OpCodes.Jmp.Value; 
     ilCodes[1] = (byte)(methodFromOtherAssembly.MetadataToken & 0xFF); 
     ilCodes[2] = (byte)(methodFromOtherAssembly.MetadataToken >> 8 & 0xFF); 
     ilCodes[3] = (byte)(methodFromOtherAssembly.MetadataToken >> 16 & 0xFF); 
     ilCodes[4] = (byte)(methodFromOtherAssembly.MetadataToken >> 24 & 0xFF); 

Он продолжает терпеть неудачу с исключением IndexNotFound.

Я хочу сделать это с помощью Raw IL byte инструкций.

ответ

6

Идентификаторы метаданных не являются глобально уникальными. Они разрешаются в контексте модуля вызывающего метода. Вы должны использовать GetMetadataToken на модуле, чтобы получить соответствующий токен. Ваш первый пример работает, потому что методы используют один и тот же модуль.

Это получит соответствующий маркер из динамического модуля:

byte[] ilCodes = new byte[5]; 
int token = module.GetMetadataToken(methodFromOtherAssembly).Token; 
ilCodes[0] = (byte)OpCodes.Jmp.Value; 
ilCodes[1] = (byte)(token & 0xFF); 
ilCodes[2] = (byte)(token >> 8 & 0xFF); 
ilCodes[3] = (byte)(token >> 16 & 0xFF); 
ilCodes[4] = (byte)(token >> 24 & 0xFF); 
+0

Майк, что я могу сказать? Работал как босс! ☺ Отличный ответ Большое спасибо! –

Смежные вопросы