C# 设置事件处理程序时使用空方法是一种不好的做法吗

C# 设置事件处理程序时使用空方法是一种不好的做法吗,c#,events,C#,Events,我有一个包含许多类的类库,在每个类中我都会引发一些事件 每个事件都有自己的事件参数集,因此我将它们作为自动属性存储在继承自EventArgs的类中。然后,我可以通过调用Invoke并传入我的EventArgs继承类的新实例来引发相关事件。这就是我的意思: using System; //My Class Library namespace MyClassLibrary { //A class public class MyClass { //My eve

我有一个包含许多类的类库,在每个类中我都会引发一些事件

每个事件都有自己的事件参数集,因此我将它们作为自动属性存储在继承自
EventArgs
的类中。然后,我可以通过调用
Invoke
并传入我的
EventArgs
继承类的新实例来引发相关事件。这就是我的意思:

using System;

//My Class Library
namespace MyClassLibrary
{
    //A class
    public class MyClass
    {
        //My event is a field
        public event EventHandler<MyEventHandler> myEvent;

        //I raise my event in this method
        public void InvokeMyEvent()
        {
            //Do some stuff

            //I raise my event here
            myEvent.Invoke(this, new MyEventHandler("The quick brown fox jumps over the lazy dog"));

            //Do some more stuff
        }
    }

    //An event handler, containing some interesting data about the event
    public class MyEventHandler : EventArgs
    {
        //Some interesting data as an automatic property
        public string MyInterestingData { get; private set; }

        //I assign the value of my intersting data in my constructor
        public MyEventHandler(string FooBar)
        {
            MyInterestingData = FooBar;
        }
    }
}
这一切编译都很好,但类库的重点肯定是要有一个可重用代码库,这当然是本文的意图。因此,我想将我的类库添加到许多项目中。在其中一些项目中,my有必要订阅
myEvent
,在其他项目中则不会,但我仍然希望在这些项目中使用该类的其他功能,并且在将来可以选择订阅
myEvent

但是,如果我在未订阅
myEvent
的项目中使用类库,则每当引发
myEvent
时,都会出现运行时错误

我在
MyClass
的构造函数中订阅了
myEvent
,并使用了如下空方法来解决这个问题:

public MyClass()
{
    myEvent += new EventHandler<MyEventHandler>(MyClass_myEvent);
}


void MyClass_myEvent(object sender, MyEventHandler e)
{

}
publicmyclass()
{
myEvent+=新事件处理程序(MyClass_myEvent);
}
void MyClass_myEvent(对象发送方,MyEventHandler e)
{
}
这意味着我可以将我的类库添加到任何项目中,实例化
MyClass
并使用它提供的其他功能,如果需要,可以订阅
myEvent
,如果不需要,则忽略
myEvent

问题是我的类中有一个空方法。想象一下这个场景,但是大约有30个事件,因此有30个空方法

几个问题

  • 我说得通吗?你至少明白我想做什么,即使你认为我在这件事上完全错了
  • 这里真的有问题吗,或者这是实现我试图实现的功能的一种相当标准的方式

  • 谢谢

    通常的做法是在引发事件之前检查
    null
    。就你而言:

    if (myEvent != null)
      myEvent.Invoke(this, new MyEventHandler("The quick brown fox jumps over the lazy dog")); 
    

    通常的做法是在引发事件之前检查
    null
    。就你而言:

    if (myEvent != null)
      myEvent.Invoke(this, new MyEventHandler("The quick brown fox jumps over the lazy dog")); 
    

    这通常是您看到以下事件模式的原因:

    private void OnMyEvent(object sender, MyEventArgs args)
    {
        var ev = myEvent;
    
        if (ev != null)
            ev(sender, args);
    }
    
    OnMyEvent(this, new MyEventArgs("The quick brown fox jumps over the lazy dog"));
    
    如果没有订阅服务器,则事件将为null。此代码获取本地副本,以确保检查点的事件不涉及竞争条件。然后调用该副本。即使这样可以防止一种形式的竞争条件,原始订户列表仍可能发生更改,而这些更改在副本中不可见,因此它不是完全线程安全的

    老实说,我从来没有考虑过,甚至没有见过你这样做。我说最好还是使用空检查,而不是空方法订户,人们期望使用前者,而不是后者

    此外,空方法路由会消耗内存/对象,而空路由只会消耗一次检查


    顺便说一句,
    MyEventHandler
    arguments类通常被称为类似于
    MyEventArgs

    的类,这通常就是您看到以下事件模式的原因:

    private void OnMyEvent(object sender, MyEventArgs args)
    {
        var ev = myEvent;
    
        if (ev != null)
            ev(sender, args);
    }
    
    OnMyEvent(this, new MyEventArgs("The quick brown fox jumps over the lazy dog"));
    
    如果没有订阅服务器,则事件将为null。此代码获取本地副本,以确保检查点的事件不涉及竞争条件。然后调用该副本。即使这样可以防止一种形式的竞争条件,原始订户列表仍可能发生更改,而这些更改在副本中不可见,因此它不是完全线程安全的

    老实说,我从来没有考虑过,甚至没有见过你这样做。我说最好还是使用空检查,而不是空方法订户,人们期望使用前者,而不是后者

    此外,空方法路由会消耗内存/对象,而空路由只会消耗一次检查


    顺便说一句,
    MyEventHandler
    arguments类通常被称为类似于
    MyEventArgs

    处理此问题的标准方法是不引发没有订阅者的事件:

    var handler = myEvent;
    if (handler != null)
    {
        handler(sender, new MyEventArgs());
    }
    

    如果在多线程场景中,单个订阅服务器在
    null
    检查和调用之间取消订阅,则分配给中间
    handler
    变量可避免获得异常。

    处理此问题的规范方法是不引发没有订阅服务器的事件:

    var handler = myEvent;
    if (handler != null)
    {
        handler(sender, new MyEventArgs());
    }
    

    如果在多线程场景中,单个订户在
    null
    检查和调用之间取消订阅,则分配给中间
    handler
    变量可避免获得异常。

    事件MyEvent的典型实现如下所示:

    protected virtual void OnMyEvent(MyEventArgs eventArgs) {
        var handler = MyEvent;
        if (handler != null) {
            handler(this, eventArgs);
        }
    }
    

    然后,无论何时您想要触发事件,都可以调用OnMyEvent而不是MyEvent。

    事件MyEvent的典型实现如下所示:

    protected virtual void OnMyEvent(MyEventArgs eventArgs) {
        var handler = MyEvent;
        if (handler != null) {
            handler(this, eventArgs);
        }
    }
    

    然后,无论何时您想要触发事件,都可以调用OnMyEvent而不是MyEvent。

    使用空处理程序初始化事件没有什么错。我总是这样做。如果要调用该事件数千次,它可能会比您想要的慢(测试、测量、决定)

    设置空处理程序时,您不必太罗嗦,您可以这样做:

    myEvent = (sender, args) => { };
    

    并避免创建方法…

    使用空处理程序初始化事件没有错。我总是这样做。如果要调用该事件数千次,它可能会比您想要的慢(测试、测量、决定)

    设置空处理程序时,您不必太罗嗦,您可以这样做:

    myEvent = (sender, args) => { };
    

    避免创建方法…

    我希望我能看到你的意思。我认为,你可以把自己的工作留给那些空洞的方法。只需按以下方式调用事件:

     //I raise my event in this method
        public void InvokeMyEvent()
        {
            //Do some stuff
    
            //Check if there are subscribers!!
            if (myEvent != null)
              myEvent.Invoke(this, new MyEventHandler("The quick brown fox jumps over the lazy dog"));
    
            //Do some more stuff
        }
    

    我希望我明白你的意思。我认为,你可以把自己的工作留给那些空洞的方法。