2008-11-06 3 views
4

У меня есть класс с именем EventConsumer, который определяет событие EventConsumed и метод OnEventConsumed следующим образом:Что такое MSIL для вызова обработчика события базового класса?

public event EventHandler EventConsumed; 

public virtual void OnEventConsumed(object sender, EventArgs e) 
{ 
    if (EventConsumed != null) 
     EventConsumed(this, e); 
} 

Мне нужно добавить атрибуты к в OnEventConsumed выполнения, поэтому я генерации подкласса с использованием System.Reflection. Испускают. То, что я хочу, это MSIL эквивалент этого:

public override void OnEventConsumed(object sender, EventArgs e) 
{ 
    base.OnEventConsumed(sender, e); 
} 

То, что я до сих пор это:

... 

MethodInfo baseMethod = typeof(EventConsumer).GetMethod("OnEventConsumed"); 
MethodBuilder methodBuilder = typeBuilder.DefineMethod("OnEventConsumed", 
                 baseMethod.Attributes, 
                 baseMethod.CallingConvention, 
                 typeof(void), 
                 new Type[] {typeof(object), 
                    typeof(EventArgs)}); 

ILGenerator ilGenerator = methodBuilder.GetILGenerator(); 

// load the first two args onto the stack 
ilGenerator.Emit(OpCodes.Ldarg_1); 
ilGenerator.Emit(OpCodes.Ldarg_2); 

// call the base method 
ilGenerator.EmitCall(OpCodes.Callvirt, baseMethod, new Type[0]); 

// return 
ilGenerator.Emit(OpCodes.Ret); 

... 

создать тип, создать экземпляр типа, и вызвать его OnEventConsumed функцию, и я получаю:

Common Language Runtime detected an invalid program. 

... что не совсем полезно. Что я делаю не так? Каков правильный MSIL для вызова обработчика события базового класса?

ответ

6

Здесь «S IL из примера приложения:


.method public hidebysig virtual instance void OnEventConsumed(object sender, class [mscorlib]System.EventArgs e) cil managed 
    { 
     .maxstack 8 
     L_0000: nop 
     L_0001: ldarg.0 
     L_0002: ldarg.1 
     L_0003: ldarg.2 
     L_0004: call instance void SubclassSpike.BaseClass::OnEventConsumed(object, class [mscorlib]System.EventArgs) 
     L_0009: nop 
     L_000a: ret 
    } 

Так что я думаю, что вы не загружаете экземпляра, потому что вы не делаете ldarg.0

0

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

public virtual void OnEventConsumed(object sender, EventArgs e) 
{ 
    if (EventConsumed != null) 
     EventConsumed(this, e); 
} 

должно быть

public virtual void OnEventConsumed(EventArgs e) 
{ 
    EventHandler handler = this.EventConsumed; 
    if (null != handler) handler(this, e); 
} 

.

Я думаю, вы должны использовать ILGenerator.EmitCalli и вы должны передать тип возвращаемого значения (я думаю, что нуль в данном случае) и передать типы аргументов - я думаю, что «нового типа [] {TYPEOF (EventArgs)}

+0

почему вторая форма? Первый работает так же хорошо. – Simon 2009-12-17 11:52:03

1

Я был на самом деле очень близко - проблема заключалась в том, что я не загружая «этот» аргумент, и что Callvirt вызывает метод подкласса, где я на самом деле хотел Зов Так что раздел будет выглядеть так:.

// load 'this' and the first two args onto the stack 
ilGenerator.Emit(OpCodes.Ldarg_0); 
ilGenerator.Emit(OpCodes.Ldarg_1); 
ilGenerator.Emit(OpCodes.Ldarg_2); 

// call the base method 
ilGenerator.EmitCall(OpCodes.Call, baseMethod, new Type[0]); 

// return 
ilGenerator.Emit(OpCodes.Ret); 

Теперь он отлично работает.

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

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