Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 代码改进:此模式的更好替代方案?_C#_Design Patterns - Fatal编程技术网

C# 代码改进:此模式的更好替代方案?

C# 代码改进:此模式的更好替代方案?,c#,design-patterns,C#,Design Patterns,在一个类似的问题中: 我在询问下面代码清单的模式名称 public class MyClass { public event EventHandler MyEvent; private bool IsHandlingEvent = false; public MyClass() { MyEvent += new EventHandler(MyClass_MyEvent); } void MyClass_MyEvent(ob

在一个类似的问题中:

我在询问下面代码清单的模式名称

  public class MyClass
  {
    public event EventHandler MyEvent;
    private bool IsHandlingEvent = false;

    public MyClass()
    {
      MyEvent += new EventHandler(MyClass_MyEvent);
    }

    void MyClass_MyEvent(object sender, EventArgs e)
    {
      if (IsHandlingEvent) { return; }

      IsHandlingEvent = true;
      {
        // Code goes here that handles the event, possibly invoking 'MyEvent' again.
        // IsHandlingEvent flag is used to avoid redundant processing.  What is this
        // technique, or pattern called.
        // ...
      }
      IsHandlingEvent = false;
    }
  }

似乎大部分的谈话都围绕着为什么我们不应该这样做,所以我认为这个问题提供了一个更好的论坛来解决这个问题和解决所有的问题。处理这个问题的更好/正确方法是什么?

这种模式存在一系列问题。如果只想调用处理程序一次,可以执行以下操作:

 protected static object _lockObj = new object();
 protected static bool _isHandled = false;    

 void MyClass_MyEvent(object sender, EventArgs e)
 {
     if(_isHandled)
       return;

     lock(_lockObj)
     {
         if(_isHandled)
            return;

         _isHandled = true;

         MyOtherPossiblyRecursiveMethod(); // Actually does all your work

         _isHandled = false;
     }
 }

 void MyOtherPossiblyRecursiveMethod()
 {
 }

这样,只有一个线程才能访问实际的工作方法。

以下内容适用于单线程和多线程场景,并且是异常安全的。。。此外,如果需要,还可以对其进行修改,以允许某种级别的可重入性(例如3个级别)

公共类MyClass
{
公共事件事件处理程序;
private int IsHandlingEvent=0;
公共MyClass()
{
MyEvent+=新事件处理程序(MyClass_MyEvent);
}
void MyClass_MyEvent(对象发送方,事件参数e)
{
//这允许在需要时通过比较(例如<3或类似值)进行嵌套
如果(联锁增量(参考IsHandlingEvent)==1)
{
试一试{
}
最后{};
} 
联锁减量(参考IsHandlingEvent);
}
}

我将使用以下内容:

using( var sl = new SoftLock() )
{
   sl.Execute(()=>{....});
}

execute将提高内部布尔值,以防止重新输入。在dispose中,将重置该标志。如果标志为false,Execute将调用lambda。这是为了确保即使发生异常(导致处理程序从未执行),标志也会变为false,这可能更好一些。当然,这并不像原始代码那样是线程安全的,但这是因为我们讨论的是防止来自同一线程的双重执行。

原始代码是防止单线程应用程序中递归的一种足够(而且非常轻量级)的方法。因此,如果在事件处理函数期间,您可以进入可能再次触发事件的代码,那么您将不会进入无限递归


但由于可能存在争用条件,代码不足以阻止来自多个线程的访问。如果您需要确保只有一个线程运行此事件,那么您应该使用更强大的锁定机制,如互斥锁或信号量。

如果在同一个线程上发生重新rais(这是a.R.讨论的场景),您是否确定锁会起作用?您可能还希望使
\u isHandled
不稳定。或者,更好的是,完全避免双重检查锁定,只检查
块内的
\u isHandled
。@LukeH如果检查
块内的\u isHandled状态,那么有时调用线程将被冻结,直到
MyOtherPossiblyRecursiveMethod()
完成并解锁块。在这里最好检查两次。@Artemix:也许,也许不是。但是在这种情况下,如果您不将
\u isHandled
标记为volatile,那么线程(理论上)可能会读取过期版本的
\u isHandled
,并且永远不会进入
块,即使它应该再次进入,如果我们在同一个线程上,互锁没有任何东西要互锁…不确定您看到了什么问题。。。这段代码只适用于单线程和多线程场景。。。如果OP通常与单线程一起工作,它将不会有任何伤害,它将实现他想要的。。。作为“奖励”,他可以在转向多线程设计时保持代码不变。。。另一个好处是异常安全。。。
using( var sl = new SoftLock() )
{
   sl.Execute(()=>{....});
}