【问题标题】:AddEventHandler using reflection to a static classAddEventHandler 使用反射到静态类
【发布时间】:2015-11-12 07:29:34
【问题描述】:

我需要将新方法附加到静态类的现有事件。 这是我的“猫”静态类,不能更改它,因为它是第 3 方。我需要添加新方法来触发同一事件myEventThis 问题显示了如何为非静态类执行此操作。但我不确定如何处理静态类。有人帮忙吗?

public static class Cat
{
 internal static event EventHandler myEvent;

public static init()
{
....
....
}

}

class Dog
{
 public static void init()
 {
   EventInfo eventInfo = typeof(Cat).GetEvent("myEvent");

      if (eventInfo != null)
      {
       Delegate handler =  Delegate.CreateDelegate(eventInfo.EventHandlerType, , newMethod); // I'm stuck here
       eventInfo.AddEventHandler(, handler);  // I'm stuck here

     }
 }

  static void newMethod()
  {

  }
}

如果myEvent 是公开的,我可以使用Cat.myEvent+= new EventHandler(newMethod);。但不幸的是internal

【问题讨论】:

  • 你有异常吗?你得到什么例外?
  • 我不知道eventInfo.AddEventHandler(arg1,newMethod); 的第一个参数arg1 是什么,因为我的类是静态的

标签: c# reflection event-handling


【解决方案1】:

您并没有走多远,但是当您尝试使用 AddEventHandler() 时,您会遇到困难。 CLR 强制事件的可访问性,即使您尝试使用反射来破解它。而且由于不是public,反射也无济于事。

你必须伸手去拿一把更大的武器。假设事件不是自定义的并且月亮位于右象限,C# 编译器会生成一个 add 访问器方法。这是一个名为add_myEvent() 的方法。请使用反编译器来验证名称,当然它实际上不是那样命名的。

您要做的第一件事是为您的事件处理程序提供正确的签名,一个与委托类型匹配的签名:

    static void newMethod(object sender, EventArgs e) {
        // etc..
    }

那么你可以这样写反射代码:

    public static void init() {
        EventInfo eventInfo = typeof(Cat).GetEvent("myEvent",
            BindingFlags.NonPublic | BindingFlags.Static);
        MethodInfo adder = typeof(Cat).GetMethod("add_myEvent",
            BindingFlags.NonPublic | BindingFlags.Static);
        MethodInfo target = typeof(Dog).GetMethod("newMethod", 
            BindingFlags.NonPublic | BindingFlags.Static);
        Delegate handler =  Delegate.CreateDelegate(eventInfo.EventHandlerType, target);
        adder.Invoke(null, new object[] { handler });
    }

【讨论】:

  • 仅供参考和进一步的读者:天真的eventInfo.AddEventHandler调用会抛出异常InvalidOperationException: Cannot add a handler to an event that doesn't have a visible add method
【解决方案2】:

你应该添加一些东西。首先,将BindingFlags 添加到GetEvent,因为该事件是静态且非公开的。默认GetEvent只返回公共实例事件:

EventInfo eventInfo = typeof(Cat).GetEvent("myEvent", BindingFlags.Static | BindingFlags.NonPublic);

其次,使用CreateDelegate 的另一个重载来对静态方法进行委托,该方法有两个参数。或者使用你的,将 null 作为第二个参数。

第三,使用null作为AddEventHandler的第一个参数。通常您将实例作为第一个参数传递,但由于此事件是静态的,因此不需要实例:

eventInfo.AddEventHandler(null, handler);  

【讨论】:

  • 如果有两个 BindingFlags,它会返回 null。但没有任何 BindingFlags ,它返回一些 EventInfo 对象
  • 你确定它是内部的吗?您确定内部部件对您的装配不可见吗? MSDN 说:“返回表示指定公共事件的 EventInfo 对象。”我稍微修改了我的答案,也许它包含更多可能对您有所帮助的信息。
【解决方案3】:

不需要 Delegate.CreateDelegate,因为 Dog 在您的控制之下。

此代码按预期工作:

namespace ConsoleApplication1
{

    public static class Cat
    {
        internal static event EventHandler myEvent;

        public static void RaiseEvent()
        {
            if (myEvent != null) myEvent(typeof(Cat), EventArgs.Empty);
        }
    }


    class Dog
    {
        public static void init()
        {
            MethodInfo addInfo = typeof(Cat).GetMethod("add_myEvent", BindingFlags.NonPublic | BindingFlags.Static);
            EventHandler handler = new EventHandler(Handler);
            addInfo.Invoke(null, new object[] { handler });
        }

        static void Handler(object sender, EventArgs e)
        {
            Console.WriteLine("Event fired");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Dog.init();
            Cat.RaiseEvent();
        }
    }
}

【讨论】:

  • 你在哪里使用EventInfo eventInfo = typeof(Cat).GetEvent("myEvent", BindingFlags.NonPublic | BindingFlags.Static);
  • 我不明白你的问题。当你想订阅 myEvent 时,你执行 Dog.Init()。在那个方法中你调用 typeof(Cat).GetEvent...
  • 您创建了eventInfo,但没有在任何地方使用它
猜你喜欢
  • 2010-11-10
  • 1970-01-01
  • 2019-09-02
  • 1970-01-01
  • 2012-03-26
  • 1970-01-01
  • 1970-01-01
  • 2018-10-30
  • 1970-01-01
相关资源
最近更新 更多