C# 4.0 C-为事件设置空委托
上述结构允许不检查是否存在任何订户:C# 4.0 C-为事件设置空委托,c#-4.0,event-handling,C# 4.0,Event Handling,上述结构允许不检查是否存在任何订户: public event EventHandler MyButtonClick = delegate { }; 代替 public virtual void OnMyButtonClick(EventHandler e) { this.MyButtonClick(this, e); } 但这真的是个好主意吗?这是唯一的好处:不检查是否有订户存在 更新:下面是一个例子 public virtual
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);
}
你不需要那样做。如果使用您类的客户端不会为MyButtonClick事件添加处理程序订阅服务器,则代码不会引发异常 这就是事件和委托的工作方式,因为它们是相同的东西,否则您将被迫向类的所有事件添加一个处理程序(假设存在任何事件) 因此,您可以执行以下操作:
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");
}
}
}
请看下面的示例:
public virtual void OnMyButtonClick(EventArgs e)
{
MyButtonClick(this, e);
}
你不需要那样做。如果使用您类的客户端不会为MyButtonClick事件添加处理程序订阅服务器,则代码不会引发异常 这就是事件和委托的工作方式,因为它们是相同的东西,否则您将被迫向类的所有事件添加一个处理程序(假设存在任何事件) 因此,您可以执行以下操作:
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");
}
}
}
请看下面的示例:
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");
}
}
这不是线程安全的。如果在空性检查之后但在调用之前删除了最终订阅,则最终可能会出现NullReferenceException,这取决于引发线程是否看到更改
因此,您可以将其改为:
public virtual void OnMyButtonClick(EventHandler e)
{
if (MyButtonClick!=null)
this.MyButtonClick(this, e);
}
。。。当然,你可能会忘记这样做,即使你不这样做,在我看来,在各地这样做是很麻烦的。所以,是的,虽然好处只是避免了无效性检查,但我认为在很多情况下,这并不是一个坏的权衡。在我看来,任何让人更难犯错误的事情都是个好主意
另一种选择是使用扩展方法:
public virtual void OnMyButtonClick(EventArgs e)
{
var handler = MyButtonClick;
if (handler != null)
{
handler(this, e);
}
}
然后将您的呼叫代码更改为:
public static void SafeInvoke(this EventHandler handler, object sender,
EventArgs e)
{
if (handler != null)
{
handler(sender, e);
}
}
并对其他事件使用相同的代码。您可能还需要EventHandler的通用表单。好的,您在这里给出的代码:
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");
}
}
这不是线程安全的。如果在空性检查之后但在调用之前删除了最终订阅,则最终可能会出现NullReferenceException,这取决于引发线程是否看到更改
因此,您可以将其改为:
public virtual void OnMyButtonClick(EventHandler e)
{
if (MyButtonClick!=null)
this.MyButtonClick(this, e);
}
。。。当然,你可能会忘记这样做,即使你不这样做,在我看来,在各地这样做是很麻烦的。所以,是的,虽然好处只是避免了无效性检查,但我认为在很多情况下,这并不是一个坏的权衡。在我看来,任何让人更难犯错误的事情都是个好主意
另一种选择是使用扩展方法:
public virtual void OnMyButtonClick(EventArgs e)
{
var handler = MyButtonClick;
if (handler != null)
{
handler(this, e);
}
}
然后将您的呼叫代码更改为:
public static void SafeInvoke(this EventHandler handler, object sender,
EventArgs e)
{
if (handler != null)
{
handler(sender, e);
}
}
并对其他事件使用相同的代码。您可能还需要EventHandler的通用表单。它是否允许您这样做?如果有人设置MyButtonClick=null;?这不应该起作用,您不能重新指定事件名称。@LKIM,您是什么意思?新建TestClass.MyButtonClick=null;?它未编译。请尝试以下操作:类测试{public event EventHandler MyEvent=delegate{};public void firevent{MyEventthis,EventArgs.Empty;}public void ClearEvent{MyEvent=null;}}}静态类程序{[STAThread]static void Main{Test t=new Test;t.firevent;t.MyEvent+=new EventHandlert\u MyEvent;t.firevent;t.ClearEvent;t.firevent;}静态无效t\u MyEventobject发送方,EventArgs e{Console.writelineet\u MyEvent;}执行不起任何作用的代码有点傻。但这并不重要,你永远不会注意到单击事件的区别。它甚至允许你这样做吗?如果有人设置MyButtonClick=null;?那不应该起作用,你不能重新分配事件名。@LKIM,你是什么意思?new TestClass.MyButtonClick=null;?它不起作用请尝试以下操作:类测试{public event EventHandler MyEvent=delegate{};public void firevent{MyEventthis,EventArgs.Empty;}public void ClearEvent{MyEvent=null;}}静态类程序{[STAThread]静态void Main{Test t=new Test;t.firevent;t.MyEvent+=new EventHandlert\u MyEvent;t.firevent;t.ClearEvent;t.firevent;}静态无效t\u MyEventobject发送方,EventArgs e{Console.writelineet\u MyEvent;}执行什么都不做的代码有点傻。但这并不重要,你永远不会注意到单击事件的区别。我确信如果没有事件处理程序,它不会抛出错误。你可以做一个测试来更好地理解,但它不会让C的作者不同意你的观点。你的更新是错误的。testClass.OnButtonCli请确认它必须是一个委托,您应该将其视为一个字段。根据MSDN:一旦一个类声明了一个事件,它就可以将该事件视为指定委托类型的字段。我确信,如果没有事件处理程序,它不会抛出错误。您可以做一个测试来更好地理解它,但C的作者不会同意您的观点。您的更新错误。testClass.OnButton单击i
t必须是一个委托,您应该将其视为一个字段。来自MSDN:一旦一个类声明了一个事件,它就可以将该事件视为指示委托类型的字段(C的作者)!哇!我问这个问题是因为你在书中的文章。这解决了我三年来遇到的一个奇怪的线程问题/我被这个答案弄糊涂了——是将一个事件分配给一个空委托,然后不进行复制/检查/调用,这是一种公认的做法,还是它不是线程安全的?@ScottSEA:它是安全的,但并没有被广泛使用。不是线程安全的是OP在问题中包含的检查/调用!哇!我问这个问题是因为你在书中的文章。这解决了我三年来遇到的一个奇怪的线程问题/我被这个答案弄糊涂了——是将一个事件分配给一个空委托,然后不进行复制/检查/调用,这是一种公认的做法,还是它不是线程安全的?@ScottSEA:它是安全的,但并没有被广泛使用。问题中包含的OP检查/调用不是线程安全的。