7

私が放出したいとしましょう

public event PropertyChangedHandler PropertyNameChanged;

どうすればいいですか?プロパティと同じように、バッキング フィールドを定義する必要がありますか? EventBuilder の使用方法と、実際にイベントを発生させる方法の例が 1 つも見つかりません。

4

2 に答える 2

7

これは古い質問であり、この回答はおそらく受け入れられないことはわかっていますが、私は Google からここに来ているので、おそらく他の人がここに来るでしょう. そんな人のために、ここに正解があります: イベントを作成するには:

  1. フィールドを作成{EventName}
  2. 同名のイベントを作成{EventName}
  3. add および remove アクセサー (メソッド)add_{EventName}を作成し、remove_{EventName}
  4. 任意の名前で raise メソッドを作成します (このステップはオプションであるため、作成しないでください)。

2番目と4番目はドミトリーの回答でカバーされていますが、ここに完全なコードがあります。もちろん、イベントに合わせて値を変更する必要がEventNameあります。EventType

  1. イベント用フィールド

var field = typeBuilder.DefineField("{EventName}", typeof({EventType}), FieldAttributes.Private);

  1. イベント

var eventInfo = typeBuilder.DefineEvent("{EventName}", EventAttributes.None, typeof({EventType}));

  1. アクセサーを追加し、アクセサーを削除します。それらは非常に似ています。

    var addMethod = typeBuilder.DefineMethod("add_{EventName}",
        MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
        CallingConventions.Standard | CallingConventions.HasThis,
        typeof(void),
        new[] { typeof({EventType}) });
    var generator = addMethod.GetILGenerator();
    var combine = typeof(Delegate).GetMethod("Combine", new[] { typeof(Delegate), typeof(Delegate) });
    generator.Emit(OpCodes.Ldarg_0);
    generator.Emit(OpCodes.Ldarg_0);
    generator.Emit(OpCodes.Ldfld, field);
    generator.Emit(OpCodes.Ldarg_1);
    generator.Emit(OpCodes.Call, combine);
    generator.Emit(OpCodes.Castclass, typeof({EventType}));
    generator.Emit(OpCodes.Stfld, field);
    generator.Emit(OpCodes.Ret);
    eventInfo.SetAddOnMethod(addMethod);

    var removeMethod = typeBuilder.DefineMethod("remove_{EventName}",
            MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
            CallingConventions.Standard | CallingConventions.HasThis,
            typeof(void),
            new[] { typeof({EventType}) });
    var remove = typeof(Delegate).GetMethod("Remove", new[] { typeof(Delegate), typeof(Delegate) });
    var generator = removeMethod.GetILGenerator();
    generator.Emit(OpCodes.Ldarg_0);
    generator.Emit(OpCodes.Ldarg_0);
    generator.Emit(OpCodes.Ldfld, field);
    generator.Emit(OpCodes.Ldarg_1);
    generator.Emit(OpCodes.Call, remove);
    generator.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
    generator.Emit(OpCodes.Stfld, field);
    generator.Emit(OpCodes.Ret);
    eventInfo.SetRemoveOnMethod(removeMethod);

  2. 上げ方。必須ではありませんが、イベントを発生させるメソッドがなければ、イベントを作成しても意味がありません。イベントデリゲートのリフレクションまたは呼び出し値を使用して、ホーカスポーカスを行っている場合を除きます。とにかく、ここにこのメソッドのコードがあります。もちろんXXXEventArgs、最初にイベント内で使用される何らかのタイプの正しいコンストラクターを取得する必要があります。このレイズ メソッドの名前も異なる場合がありますが、一般的には次のパターンに従う方が適切です (以下のように)。

    var methodBuilder = typeBuilder.DefineMethod("On{EventName}",
        MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig |
        MethodAttributes.NewSlot, typeof(void),
        new[] { typeof(string) });
    var generator = methodBuilder.GetILGenerator();
    var returnLabel = generator.DefineLabel();
    var eventArgsCtor = typeof({XXXEventArgs}).GetConstructor(new[] { typeof(string) });
    generator.DeclareLocal(typeof({EventType}));
    generator.Emit(OpCodes.Ldarg_0);
    generator.Emit(OpCodes.Ldfld, field);
    generator.Emit(OpCodes.Stloc_0);
    generator.Emit(OpCodes.Ldloc_0);
    generator.Emit(OpCodes.Brfalse, returnLabel);
    generator.Emit(OpCodes.Ldloc_0);
    generator.Emit(OpCodes.Ldarg_0);
    generator.Emit(OpCodes.Ldarg_1);
    generator.Emit(OpCodes.Newobj, eventArgsCtor);
    generator.Emit(OpCodes.Callvirt, typeof(PropertyChangedEventHandler).GetMethod("Invoke"));
    generator.MarkLabel(returnLabel);
    generator.Emit(OpCodes.Ret);
    eventInfo.SetRaiseMethod(methodBuilder);
    return methodBuilder;

    また、このメソッドは仮想または保護 ( ) である必要はありませんが、MethodAttributes.Familyこのメソッドを非公開にしてオーバーライド可能にすることをお勧めします。パラメーターの型も異なり、XXXEventArgs型コンストラクターと互換性がある必要があります。このメソッドでより多くのパラメータを使用することもできますが、IL がより複雑になるため、使用しないことをお勧めします (自分自身と正気を保つために、IL で行うことはできるだけ少なくする必要があります)。

于 2016-10-18T19:40:04.640 に答える
1
  TypeBuilder myClass =
     myModule.DefineType("MyClass", TypeAttributes.Public);

  MethodBuilder onPropertyNameChanged= myClass.DefineMethod("OnPropertyNameChanged",
     MethodAttributes.Public, typeof(void), new Type[]{typeof(Object)});
  ILGenerator onPropertyNameChangedIl= onPropertyNameChanged.GetILGenerator();
  onPropertyNameChangedIl.Emit(OpCodes.Ret);

  // Create the event.
  EventBuilder propertyNameChanged= myClass.DefineEvent("PropertyNameChanged", EventAttributes.None,
     typeof(PropertyChangedHandler)); //should be declared before
  propertyNameChanged.SetRaiseMethod(onPropertyNameChanged);

  myClass.CreateType();
于 2012-11-29T05:57:37.793 に答える