多个事件获得在单例中声明的字段的不同实例?

时间:2015-02-17 12:25:36

标签: c# events

编辑:我的不好,没有暴力事件的行为。错误是代码中的其他地方。感谢大家的帮助。请忽略此问题

请有人向我解释这里发生了什么。我遇到了意外的事件行为。

有一个单身人士课程:

internal class QueueListener
{
   private static readonly object QueueChangeLock = new object();
   private readonly List<IQueuedJobExecutioner> jobsQueue = new List<IQueuedJobExecutioner>();

  // Here comes singleton private constructor, Instance property, all classic.
  // Important line in constructor is this:
  QueueManager.NewJobQueued += NewJobQueuedHandler;

private void NewJobQueuedHandler(object sender, NewJobQueuedEventArgs args)
        {
            lock (QueueChangeLock)
            {
                // This is the problematic place, note this!
                jobsQueue.Add(args.QueuedJobExecutioner);
            }
        }  
}

现在有第二堂课:

public class QueueManager
{
   public static event NewJobQueuedEventHandler NewJobQueued;

   protected void RaiseNewJobQueuedEvent(IQueuedJobExecutioner queuedJobExecutioner)
        {
            if (NewJobQueued != null)
            {
                NewJobQueued(this, new NewJobQueuedEventArgs { QueuedJobExecutioner = queuedJobExecutioner });
            }
        }
}

两个类都驻留在服务器上。通过WCF调用客户端执行new QueueManager().MyMethod(),调用RaiseNewJobQueuedEvent

一切正常,但如果几乎同时发出两个事件,我会在调试器中看到有问题的地方(请参阅QueueListener中的注释):

  1. 第一个事件来了。 jobsQueue没有会员。
  2. jobsQueue.Add()被执行。 jobsQueue有1名成员。
  3. 第二个事件来了。 jobsQueue没有会员!怎么样?这是一个单身人士,我们只是添加了一个成员!
  4. jobsQueue.Add()被执行。 jobsQueue有1名成员。再次。第2步中添加的成员已丢失。
  5. 不判断设计本身(它有一些“历史”原因),为什么会发生这种情况?这种预期的行为和事件是否在某种程度上得到了jobsQueue的快照,或者这是无意义的,我只是错过了一些难题的部分?

    编辑: 我会说它是一个单例,并且是这样实现的(原始帖子中省略了这些行):

    class QueueListener
    {
      private static readonly object SyncRoot = new object();
      private QueueListener()
            {
    //...
            }
    
            public static QueueListener Instance
            {
                get
                {
                    if (instance == null)
                    {
                        lock (SyncRoot)
                        {
                            if (instance == null)
                            {
                                instance = new QueueListener();
                            }
                        }
                    }
    
                    return instance;
                }
            }
    }
    

2 个答案:

答案 0 :(得分:0)

Yuval是正确的,你的班级不是单身人士。当您使用公共静态方法创建实例和私有构造函数时,将创建单例。私有构造函数确保创建实例的唯一方法是通过公共方法。

有关详细信息,请参阅https://msdn.microsoft.com/en-us/library/ff650316.aspx

答案 1 :(得分:0)

你的QueueListener课程实际上不是单身人士。这对您来说意味着您正在创建它的多个实例。要解决此问题,您必须在类声明中添加static关键字,并声明static构造函数。尝试将您的课程更改为如下所示:

internal static class QueueListener
{
       private static readonly object QueueChangeLock = new object();
       private static readonly List<IQueuedJobExecutioner> jobsQueue = new List<IQueuedJobExecutioner>();

    // This is the singleton constructor that will be called
    static QueueListener()
    {
      // Here comes singleton private constructor, Instance property, all classic.
      // Important line in constructor is this:
      QueueManager.NewJobQueued += NewJobQueuedHandler;
    }

    // Rest of class code...
}