C# - 为事件设置空委托

时间:2012-07-23 08:52:33

标签: c#-4.0 event-handling

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");
        }
    }
}

2 个答案:

答案 0 :(得分:4)

嗯,你在这里给出的代码:

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

不是线程安全的。如果在无效检查之后删除了最终订阅,但在调用之前 ,则可能最终得到NullReferenceException(取决于是否"提升& #34;线程看到了变化)。

所以你可以改为:

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>的通用表单。

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