【问题标题】:Why can't I directly pass a custom event args class into a method subscribing to my event?为什么我不能直接将自定义事件 args 类传递给订阅我的事件的方法?
【发布时间】:2012-07-16 16:59:34
【问题描述】:

即使我的自定义事件 args 类直接继承自 EventArgs,为什么我不能直接将自定义事件参数传递给订阅我的事件的方法?

例如,考虑以下两个类。一个是我要使用的类,另一个继承自EventArgs,并包含一些与事件相关的附加信息:

using System;

namespace ConsoleApplication11
{
    class MyClass
    {
        public event EventHandler MyEvent;

        public void MyMethod(int myNumber)
        {
            Console.WriteLine(myNumber);

            if(myNumber == 7)
            {
                MyEvent.Invoke(null, new MyCustomEvent() { Foo = "Bar" });
            }
        }
    }

    class MyCustomEvent : EventArgs
    {
        public string Foo { get; set; }
    }
}

因此,如果将数字 7 传递给 MyMethod,我想调用 MyEvent,将 MyCustomEvent 类的新实例传递给订阅我的事件的任何方法。

我像这样从我的主程序订阅这个:

using System;

namespace ConsoleApplication11
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass myClass = new MyClass();
            myClass.MyEvent += new EventHandler(myClass_MyEvent);

            for (int i = 0; i < 9; i++)
            {
                myClass.MyMethod(i);
            }
        }

        static void myClass_MyEvent(object sender, EventArgs e)
        {
            //Do Stuff
        }
    }
}

即使我在调用事件时传入了 MyCustomEvent 对象,但如果我将订阅我的事件的方法中的第二个参数更改为 MyCustomEvent 对象,我会收到编译错误。我需要将EventArgs 对象显式转换为MyCustomEvent,然后才能访问类中的任何其他字段/方法等。

当使用具有许多不同事件的对象时,每个对象都有一个唯一相关的自定义 EventArgs 类,跟踪每个订阅每个事件的方法中的 EventArgs 需要强制转换为可以得到一点乱七八糟的。

如果我可以将我的自定义 EventArgs 类直接传递到订阅我的事件的方法中会容易得多。

这可能吗?

谢谢

【问题讨论】:

    标签: c# .net events


    【解决方案1】:

    不要将您的事件声明为 EventHandler 类型,而是创建一个专门使用您的自定义事件 args 类的新委托:

    public delegate void MyEventHandler(object sender, MyEventArgs args);
    public event MyEventHandler MyEvent;
    

    现在您可以直接传递参数而无需强制转换。

    另一种选择是使用通用的EventHandler&lt;T&gt;

    public event EventHandler<MyEventArgs> MyEvent;
    

    我更喜欢前者,因为您可以为委托类型指定一个更具描述性的名称,尽管后者要快一些。

    【讨论】:

      【解决方案2】:

      使用EventHandler 的通用版本声明您的事件:

      public event EventHandler<MyCustomEvent> MyEvent;
      

      【讨论】:

        【解决方案3】:

        与其使用默认事件处理程序,不如只定义适合您想要实现的签名的自己的事件处理程序...

        public delegate void MyEventHandler(object sender, MyCustomEventArgs e)
        public event MyEventHandler MyEvent;
        

        【讨论】:

          【解决方案4】:

          如果我理解你的问题是错误的,请原谅我。没有看到任何自定义 EventArgs 类,我有点困惑。

          你不能像

          那样做一个方法签名
          static void myClass_MyEvent(object sender, CustomEventArgs e)
          

          对于需要

          的事件
          static void myClass_MyEvent(object sender, EventArgs e)
          

          这就是反向多态,而多态不能反向工作。

          假设您的事件访问了e.OnlyInCustomEventArgs,但却传递了基础对象EventArgs。然后合同就被打破了。

          现在你可以做的是

          static void myClass_MyEvent(object sender, EventArgs e)
          {
              CustomEventArgs cea = (CustomEventArgs)e;
          }
          

          【讨论】:

            【解决方案5】:

            这是正确实现的自定义 arg 事件处理程序的完整代码。

            class MyClass
            {
                public event EventHandler<MyCustomEventArgs> MyEvent;
            
                public void MyMethod(int myNumber)
                {
                    Console.WriteLine(myNumber);
            
                    if (myNumber == 7)
                    {
                        MyEvent.Invoke(null, new MyCustomEventArgs() { Foo = "Bar" });
                    }
                }
            }
            
            class MyCustomEventArgs : EventArgs
            {
                public string Foo { get; set; }
            }
            
            
            class Program
            {
                static void Main(string[] args)
                {
                    MyClass myClass = new MyClass();
                    myClass.MyEvent += new EventHandler<MyCustomEventArgs>(myClass_MyEvent);
            
                    for (int i = 0; i < 9; i++)
                    {
                        myClass.MyMethod(i);
                    }
                }
            
                //This is the method signature that you need to use to handle the event
                static void myClass_MyEvent(object sender, MyCustomEventArgs e)
                {
                    Console.WriteLine(e.Foo); // prints "Bar"
                    //Do Stuff
                }
            
                //If you need to handle more than one type of custom event args
                static void myClass_MyEvent<T>(object sender, T e) where T : EventArgs
                {
                    //Do Stuff
                }
            }
            

            【讨论】:

              猜你喜欢
              • 2019-05-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-10-24
              • 1970-01-01
              • 2018-11-06
              • 2012-11-15
              • 1970-01-01
              相关资源
              最近更新 更多