2012-06-21 3 views
2

Я в настоящее время играет с отражением и у меня есть проблемы с моим коротким кодом:Reflection.Emit Операция ошибка может дестабилизировать выполнения

public class Test 
{ 
    public Test() 
    { 

    } 
    public string Call() 
    { 
     string called = "Called"; 
     return called; 
    } 
} 

и использование:

var method = new DynamicMethod("dummy", null, Type.EmptyTypes); 
var g = method.GetILGenerator(); 

g.DeclareLocal(typeof(Object)); 
g.Emit(OpCodes.Newobj, typeof(Test).GetConstructor(Type.EmptyTypes)); 
g.Emit(OpCodes.Stloc, 0); 
g.Emit(OpCodes.Nop); 
g.Emit(OpCodes.Ldloc, 0); 
g.Emit(OpCodes.Call, typeof(Test).GetMethod("Call", new Type[]{})); 
g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]{ typeof(string) })); 
g.Emit(OpCodes.Nop); 
//g.Emit(OpCodes.Pop); - used in debugging 
g.Emit(OpCodes.Ret); 

var action = (Action)method.CreateDelegate(typeof(Action)); 
action(); 

Console.Read(); 

Зв Я пытаюсь создать новый метод во время выполнения. В этом методе я создаю новый пустой тестовый экземпляр. Затем я пытаюсь установить его в location (0), который имеет тип if Object. Затем я загружаю его, и я называю его методом Call, чтобы получить строку. В конце я пытаюсь поставить строковый результат на экран. Мой код работает с 'Ldloc_0'. Там, когда вызывается метод «Call», возникает ошибка. Кто-нибудь знает, как решить эту проблему? Пожалуйста помоги.

ответ

4

Call(...) и является методом экземпляра; попробуйте использовать CallVirt вместо OpCodes.Call. Console.WriteLine - Статический метод, поэтому следует использовать Call.

Если у вас есть сомнения, просто напишите C# для того, что вы хотите испустить, и посмотрите на него в отражателе.

Обратите внимание, что Ldloc/0 с последующим звонком/callvirt будет непроверяемый - должны иметь брошенное там тоже:

g.DeclareLocal(typeof(Object)); 
g.Emit(OpCodes.Newobj, typeof(Test).GetConstructor(Type.EmptyTypes)); 
g.Emit(OpCodes.Stloc, 0); 
g.Emit(OpCodes.Ldloc, 0); 
g.Emit(OpCodes.Castclass, typeof(Test)); 
g.Emit(OpCodes.Callvirt, typeof(Test).GetMethod("Call", new Type[] { })); 
g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", 
     new Type[] { typeof(string) })); 
g.Emit(OpCodes.Ret); 

или лучше:

g.DeclareLocal(typeof(Test)); 
g.Emit(OpCodes.Newobj, typeof(Test).GetConstructor(Type.EmptyTypes)); 
g.Emit(OpCodes.Stloc_0); 
g.Emit(OpCodes.Ldloc_0); 
g.Emit(OpCodes.Callvirt, typeof(Test).GetMethod("Call", new Type[] { })); 
g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", 
      new Type[] { typeof(string) })); 
g.Emit(OpCodes.Ret); 

или лучший:

g.Emit(OpCodes.Newobj, typeof(Test).GetConstructor(Type.EmptyTypes)); 
g.Emit(OpCodes.Callvirt, typeof(Test).GetMethod("Call", new Type[] { })); 
g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", 
      new Type[] { typeof(string) })); 
g.Emit(OpCodes.Ret); 
+0

№ Без изменений. Когда я не устанавливаю объект в местоположение и не загружаю его, он работает с обычным вызовом. Я попытался изменить его, и я все еще получаю такую ​​же ошибку. – user35443

+0

@ user35443 2 секунды затем ... запуск IDE ... –

+0

доказательство: http://prntscr.com/awk05 – user35443

1

Объявить локальную переменную типа «Тест» вместо «Объект»:

g.DeclareLocal(typeof(Test)); 

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

  • Нет связанных вопросов^_^