可以在C#中使用带有非默认构造函数的单例吗?

时间:2011-04-04 14:18:50

标签: c# singleton parameter-passing

这个问题略有不同:Possible to use a singleton with a non-default constructor in C#?

我有一个为其构造函数提取参数的类。我想制作这个单例,以便在初始化单例时获取参数,因此在每次检索实例时都不需要传递参数。

我的解决方案(这不是优雅的)是有一个CreateInstance()静态方法,它接受参数并构造单例实例。然后,我将有另一个静态方法GetInstance(),它将无参数获取单例实例。在代码中,我需要在调用GetInstance之前确保逻辑调用CreateInstance。但是,我无法在编译时强制执行此操作。但是,如果在GetInstance之前调用异常,我可以在运行时检查异常{/ 1}}。

无论如何,我可以通过编译时执行来实现这种行为吗?或者至少,是否有更好的方法来做同样的事情?

6 个答案:

答案 0 :(得分:5)

在编译时无法做到这一点,因为这就像询问编译器“你能证明在执行代码Y之前,在存在多个线程的情况下代码X永远不会被执行吗?”。它无法完成。

至于你的设计的运行时行为,我认为这是一如既往的好。

通过在单例类中公开Func<SingletonType>属性,可以使其稍微好一些。当有人要求单例实例并且尚未创建实例时,您的类将调用此“工厂方法”来构造单例。如果工厂方法是null,那么您可以使用一些默认参数抛出异常或(如果适用)构造。

这样做基本上推迟了单身人士的构建,直到第一次实际需要它为止,所以一些改进。但基本原则是一样的。

<强>更新

正如LukeH所指出的,这几乎是Lazy<T>所做的(仅限.NET 4)。如果可能的话,使用那个,而不是自己编写。

答案 1 :(得分:1)

在经典的单身人士中,真正的魔法发生在static readonly中,它会在使用后立即创建实例:

public class MySingleton
{
    private static readonly _instance = new MySingleton();

    private MySingleton() {}

    public static MySingleton Instance
    {
        get
        {
            return _instance;
        }
    }

}

如果你有要传递给构造函数的参数,你必须自己实现锁定(注意if的双lock个问题:

public class MySingletonWithConstructor
{
    private static _instance;
    private static object _lock = new Object();

    private MySingletonWithConstructor(string myArg) 
    {
        // ... do whatever necessary
    }

    public static MySingletonWithConstructor Instance
    {
        get
        {
            if(_instance==null)
            {
                lock(_lock)
                {
                    if(_instance==null) // double if to prevent race condition
                    {
                        _instance = new MySingletonWithConstructor("Something");
                    }
                }
            }
            return _instance;
        }
    }

}

答案 2 :(得分:0)

如果单例对象不存在,您可以GetInstance()调用CreateInstance()方法。

答案 3 :(得分:0)

我会这样做。您可能需要添加锁或其他内容以确保:

 public class ClassA {     
    private static ClassA instance;

    private int param;

    private ClassA(int param) {
       this.param = param;
    }

    public static ClassA getInstance() {
       if (instance == null) {
          throw new CustomException("Not yet initialised");
       } else {
          return instance;
       }
    }

    public static void createInstance(int param) {
       if (instance == null) {
          instance = new ClassA(param);
       }
    }
}

答案 4 :(得分:0)

在你的GetInstance()方法中,如果你的值为null,为什么不调用CreateInstance,那么你就是懒惰的初始化..

答案 5 :(得分:0)

使用CreateInstance()作为Lazy<T>的加载器并让GetInstance返回Lazy.Value(您可能希望创建一个静态只读字段,设置为= thelazy.Value以确保单个条目进入的CreateInstance())