Extension方法线程安全吗?

SwD*_*n81 6 c# extension-methods thread-safety

这个Extension方法线程安全吗?

   public static class Extensions
   {
      public static void Raise<T>(this EventHandler<T> handler,
        object sender, T args) where T : EventArgs
      {
         if (handler != null) handler(sender, args);
      }
   }
Run Code Online (Sandbox Code Playgroud)

或者我需要将其改为此吗?

   public static class Extensions
   {
      public static void Raise<T>(this EventHandler<T> handler,
        object sender, T args) where T : EventArgs
      {
         var h = handler;
         if (h!= null) h(sender, args);
      }
   }
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 9

你发现了一个有趣的环洞,它让每个人都绊倒了.不,它不是线程安全的.

虽然看起来像是通过方法参数复制了EventHandler <>引用,但这不是在运行时发生的事情.扩展方法需要内联,就像常规实例方法一样.事实上,由于它太小,因此有可能被内联.没有副本,你必须自己制作一个.


Eri*_*ert 7

这两个版本都不是线程安全的,这取决于你对"线程安全"的意思.考虑你的第二个版本:

   var h = handler;          
   if (h!= null) 
       h(sender, args);
Run Code Online (Sandbox Code Playgroud)

"handler"是某个字段的副本,其中包含一个不可变委托.假设在null检查之后,该字段在另一个线程上变为"null".在这种情况下,您的代码不会崩溃,因为您已经复制了原始的非null值.但仅仅不崩溃并不会使程序线程安全.一个不会崩溃但仍会产生错误结果的程序仍然不是线程安全的.

假设当另一个线程将事件字段设置为null时,它还会改变某些状态,即先前的内容需要正确运行.您现在要运行一个事件处理程序,该处理程序依赖于在另一个线程上突变的状态; 你正在运行一个陈旧的事件处理程序.

没有简单的方法可以防止这个问题; 如果那是你所处的情况,那么你将不得不非常仔细地设计你的线程逻辑,以便处理这种情况.