如何使用EventBuilder创建活动?

时间:2012-11-29 05:37:54

标签: c# .net clr

假设我想发光

public event PropertyChangedHandler PropertyNameChanged;

我该怎么做?我是否需要定义像我属性一样的支持字段?我找不到如何使用EventBuilder的单个示例,以及如何实际引发事件?

2 个答案:

答案 0 :(得分:3)

我知道这是一个老问题,这个答案可能永远不会被接受,但我从谷歌来到这里,所以可能其他人会来这里。只为这些人,这是一个正确的答案: 要创建和事件,您必须:

  1. 创建字段{EventName}
  2. 使用相同名称{EventName}
  3. 创建活动
  4. 创建添加和删除访问者(方法)add_{EventName}remove_{EventName}
  5. 使用某个任意名称创建raise方法(或者不要,因为此步骤是可选的)
  6. Dmitry的回答涵盖了第二次,但这里有一个完整的代码。当然,您必须更改EventNameEventType以获取与您的活动相符的值。

    1. 活动领域
    2. var field = typeBuilder.DefineField("{EventName}", typeof({EventType}), FieldAttributes.Private);

      1. 事件
      2. 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. 提高方法。不是必需的,但是如果你没有提高它的方法,那么创建事件真的没有意义。除非你正在做一些反射或调用事件代表值的hocus-pocus。 无论如何这里是这个方法的代码。当然,您必须首先获取在事件内使用的某些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来帮助你自己和你的理智)。

答案 1 :(得分: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();