2008-11-06 29 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); 

现在它工作正常。

相关问题