Raise event thread safely - best practice(安全地引发事件线程 - 最佳实践)
问题描述
为了引发事件,我们使用 OnEventName 方法,如下所示:
In order to raise an event we use a method OnEventName like this:
protected virtual void OnSomethingHappened(EventArgs e)
{
EventHandler handler = SomethingHappened;
if (handler != null)
{
handler(this, e);
}
}
但是和这个有什么区别呢?
But what is the difference with this one ?
protected virtual void OnSomethingHappened(EventArgs e)
{
if (SomethingHappened!= null)
{
SomethingHappened(this, e);
}
}
显然第一个是线程安全的,但为什么以及如何?
Apparently the first is thread-safe, but why and how ?
不需要开一个新线程吗?
It's not necessary to start a new thread ?
推荐答案
在检查空值之后调用之前,SomethingHappened
变为 null
的可能性很小.然而,MulticastDelagate
s 是不可变的,所以如果你首先分配一个变量,对变量进行空检查并通过它调用,你可以安全地避免这种情况(自我插件:我写了一个 不久前关于此的博文).
There is a tiny chance that SomethingHappened
becomes null
after the null check but before the invocation. However, MulticastDelagate
s are immutable, so if you first assign a variable, null check against the variable and invoke through it, you are safe from that scenario (self plug: I wrote a blog post about this a while ago).
虽然硬币有背面;如果您使用临时变量方法,您的代码会受到 NullReferenceException
的保护,但事件可能会在事件侦听器与事件分离后调用.这只是以最优雅的方式处理的事情.
There is a back side of the coin though; if you use the temp variable approach, your code is protected against NullReferenceException
s, but it could be that the event will invoke event listeners after they have been detached from the event. That is just something to deal with in the most graceful way possible.
为了解决这个问题,我有时会使用一种扩展方法:
In order to get around this I have an extension method that I sometimes use:
public static class EventHandlerExtensions
{
public static void SafeInvoke<T>(this EventHandler<T> evt, object sender, T e) where T : EventArgs
{
if (evt != null)
{
evt(sender, e);
}
}
}
使用该方法,您可以像这样调用事件:
Using that method, you can invoke the events like this:
protected void OnSomeEvent(EventArgs e)
{
SomeEvent.SafeInvoke(this, e);
}
这篇关于安全地引发事件线程 - 最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:安全地引发事件线程 - 最佳实践
基础教程推荐
- MS Visual Studio .NET 的替代品 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01
- 将 XML 转换为通用列表 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- 如何激活MC67中的红灯 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30