سؤال

لدي فصل يسمى EventConsumer والذي يحدد حدث Event Couped وطريقة مخصصة على النحو التالي:

public event EventHandler EventConsumed;

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

أحتاج إلى إضافة سمات إلى وقت التشغيل عند Oneventcumed ، لذلك أقوم بإنشاء فئة فرعية باستخدام system.reflection.emit. ما أريده هو ما يعادل 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);

...

أقوم بإنشاء النوع ، وإنشاء مثيل من النوع ، وأتصل بوظيفة OneVentcumest ، وأحصل على:

Common Language Runtime detected an invalid program.

... وهو ليس مفيدًا تمامًا. ما الخطأ الذي افعله؟ ما هو MSIL الصحيح لاستدعاء معالج حدث الفئة الأساسية؟

هل كانت مفيدة؟

المحلول

إليك 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

نصائح أخرى

كنت قريبًا حقًا - كانت المشكلة أنني لم أكن أقوم بتحميل الحجة "هذه" ، وأن 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);

الآن يعمل بشكل جيد.

استخدام

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 ويجب أن تمرر نوعًا من قيمة الإرجاع (أعتقد أن NULL في هذه الحالة) وتمرير أنواع الوسائط - أعتقد "Type New [] {typeof (eventArgs)}

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top