Singleton工厂,有点

时间:2010-02-01 00:33:50

标签: c# object-lifetime

很抱歉,如果在其他地方已经回答了这个问题......我发现很多关于类似事情的帖子但不一样。

我想确保一次只存在一个对象实例,但我不希望该对象保留在其自然生命周期之外,就像Singleton模式一样。

我正在编写一些代码,每分钟处理一个列表(由我无法控制的外部代码)。目前我只是每次创建一个新的“处理”对象,当它超出范围时会被破坏,正常情况下。但是,有时处理时间可能超过一分钟,因此下一个触发器将在新线程中创建处理类的第二个实例。

现在,我希望有一种机制,一次只能有一个实例...比如某种工厂,它一次只允许一个对象。对工厂的第二次调用将返回null,而不是新对象,比如说。

到目前为止,我的(糟糕的)解决方案是将Factory类型对象作为处理器类的嵌套类:

class XmlJobListProcessor
{
    private static volatile bool instanceExists = false;

    public static class SingletonFactory
    {
        private static object lockObj = new object();

        public static XmlJobListProcessor CreateListProcessor()
        {
            if (!instanceExists)
            {
                lock (lockObj)
                {
                    if (!instanceExists)
                    {
                        instanceExists = true;
                        return new XmlJobListProcessor();
                    }
                    return null;
                }
            }
            return null;
        }
    }

    private XmlJobListProcessor() { }
    ....
    }

我正在考虑为XmlJobListProcessor类编写一个显式析构函数,将“instanceExists”字段重置为false。

我意识到这是一个非常可怕的设计。工厂应该是一个独立的类......它只是嵌套,所以它和实例析构函数都可以访问volatile布尔值...

任何人都有更好的方法吗?干杯

5 个答案:

答案 0 :(得分:2)

我知道.NET 4并没有被广泛使用,但最终它将成为你将拥有:

private static readonly Lazy<XmlJobListProcessor> _instance =
    new Lazy<XmlJobListProcessor>(() => new XmlJobListProcessor());

然后您可以通过_instance.Value访问它,并在第一次请求时对其进行初始化。

答案 1 :(得分:1)

您的原始示例使用了双重检查锁定,应该不惜一切代价避免使用。

有关如何正确初始化Singleton的信息,请参阅msdn Singleton implementation

答案 2 :(得分:0)

只需制作一个并保持它,不要破坏并每分钟创建它

“尽可能减少活动部件”

答案 3 :(得分:0)

我会上课并保留它。当然我不会使用析构函数(如果你的意思是~myInstance())......这会增加GC时间。另外,如果一个进程花费的时间超过一分钟,那么如果只返回一个空值,那么对于假设要处理的数据你会怎么做呢?

保持实例处于活动状态,并可能构建一个缓冲机制,以便在处理器类繁忙时继续接收输入。您可以查看:

if ( isBusy == true )
{
     // add data to bottom of buffer
}
else
{
     // call processing
}

答案 4 :(得分:0)

我认为每个人都没有重新实例化处理器对象和BillW关于队列的观点,所以这是我的混蛋mashup解决方案:

public static class PRManager
{
    private static XmlJobListProcessor instance = new XmlJobListProcessor();
    private static object lockobj = new object();

    public static void ProcessList(SPList list)
    {
         bool acquired = Monitor.TryEnter(lockobj);
            try
            {
                if (acquired)
                {
                    instance.ProcessList(list);
                }
            }
            catch (ArgumentNullException)
            {
            }
            finally
            {
                Monitor.Exit(lockobj);
            }
    }
}

处理器作为静态成员长期保留(这里,长期对象保留不是问题,因为它没有状态变量等)如果在lockObj上获取了锁,则不处理请求并且调用线程将继续其业务。

为反馈人员喝彩。 Stackoverflow将确保我的实习! ; d