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