1
public event EventHandler MyButtonClick = delegate { };

上面的结构允许不检查是否有任何订阅者:

public virtual void OnMyButtonClick(EventHandler e)
        {
            this.MyButtonClick(this, e);
        }

代替

  public virtual void OnMyButtonClick(EventHandler e)
            { 
                if (MyButtonClick!=null)
                   this.MyButtonClick(this, e);
            }

但这真的是个好主意吗?这是唯一的好处:不检查是否存在任何订阅者?

更新:这是示例

namespace ConsoleApplication2
{
    public class TestClass
    {
        public event EventHandler MyButtonClick;
            //= delegate { };

        public void OnButtonClick(EventArgs e)
        {
            MyButtonClick(this, e);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var testClass = new TestClass();
            //it throws an exception
            testClass.OnButtonClick(new EventArgs());

            // if you add an handler it will call it

            testClass.MyButtonClick += myCustomHandler;
            testClass.OnButtonClick(new EventArgs()); // myCustomHandler has been invoiked

        }

        private static void myCustomHandler(object sender, EventArgs e)
        {
            Console.WriteLine("myCustomHandler has been invoiked");
        }
    }
}
4

2 回答 2

4

好吧,你在这里给出的代码:

public virtual void OnMyButtonClick(EventHandler e)
{ 
    if (MyButtonClick!=null)
       this.MyButtonClick(this, e);
}

不是线程安全的。如果在无效性检查之后但调用之前删除了最终订阅,您可能会得到一个NullReferenceException(取决于“提升”线程是否看到更改)。

因此,您可以将其更改为:

public virtual void OnMyButtonClick(EventArgs e)
{ 
    var handler = MyButtonClick;
    if (handler != null)
    {
        handler(this, e);
    }
}

......但当然你可能会忘记这样做,即使你不这样做,在整个地方都这样做很麻烦,IMO。所以是的,虽然好处是“仅”是为了避免无效检查,但我想说在许多情况下这并不是一个糟糕的权衡。IMO,任何使犯错更难的事情都是个好主意。

另一种选择是有一个扩展方法:

public static void SafeInvoke(this EventHandler handler, object sender,
                              EventArgs e)
{
    if (handler != null)
    {
        handler(sender, e);
    }       
}

然后将您的调用代码更改为:

public virtual void OnMyButtonClick(EventArgs e)
{
    MyButtonClick.SafeInvoke(this, e);
}

(并对其他事件使用相同的代码)。您可能还需要一个通用表格EventHandler<T>

于 2012-07-23T16:41:28.083 回答
0

你不需要这样做。如果使用您的类的客户端不会为MyButtonClick事件添加处理程序(订阅者),则代码不会引发异常。

这就是事件的工作方式(和委托是一样的),否则你将被迫为一个类的所有事件添加一个处理程序(假设有任何事件)

所以您可以执行以下操作:

public virtual void OnMyButtonClick(EventArgs e)
{ 
   MyButtonClick(this, e);
}

看看下面的例子:

public class TestClass
{
    public event EventHandler MyButtonClick = delegate { };

    public void ButtonClick(EventArgs e)
    {
        MyButtonClick(this,e);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var testClass=new TestClass();
        testClass.ButtonClick(new EventArgs());

        // if you add an handler it will call it

        testClass.MyButtonClick += myCustomHandler;
        testClass.ButtonClick(new EventArgs()); // myCustomHandler has been invoiked

    }

    private static void myCustomHandler(object sender, EventArgs e)
    {
        Console.WriteLine("myCustomHandler has been invoiked");
    }
}
于 2012-07-23T08:58:36.620 回答