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

是否可以在C#中使用带有非默认构造函数的单例?,c#,singleton,parameter-passing,C#,Singleton,Parameter Passing,这是这个问题的一个细微差异: 我有一个类,它为它的构造函数接受参数。我希望使这个单例在初始化单例时使用参数,因此不需要在每次检索实例时传递参数 我的解决方案(不是很优雅)是使用一个CreateInstance()static方法来获取参数并构造singleton实例。然后,我将使用另一个静态方法GetInstance(),该方法将是无参数的,以获取singleton实例。在代码中,我需要确保在调用GetInstance之前,逻辑调用CreateInstance。但是,我不能在编译时强制执行此操作

这是这个问题的一个细微差异:

我有一个类,它为它的构造函数接受参数。我希望使这个单例在初始化单例时使用参数,因此不需要在每次检索实例时传递参数

我的解决方案(不是很优雅)是使用一个
CreateInstance()
static方法来获取参数并构造singleton实例。然后,我将使用另一个静态方法
GetInstance()
,该方法将是无参数的,以获取singleton实例。在代码中,我需要确保在调用GetInstance之前,逻辑调用
CreateInstance
。但是,我不能在编译时强制执行此操作。但是,我可以在运行时通过在
GetInstance
中抛出异常来检查它是否在
CreateInstance
之前调用


我是否可以通过编译时强制实现这种行为?或者至少,有没有更好的方法来做同样的事情呢?

在编译时没有办法这样做,因为这就像问编译器“你能证明在有多个线程的情况下,在执行代码Y之前,代码X永远不会被执行吗?”。这是不可能做到的

至于设计的运行时行为,我认为这是最好的

通过在singleton类中公开
Func
属性,可以使它稍微好一点。当有人请求单例实例而实例尚未创建时,您的类将调用此“工厂方法”来构造单例。如果工厂方法为
null
,则抛出异常或(如果适用)使用某些默认参数构造

这实际上是将单例的构造推迟到第一次真正需要它时,所以这是一些改进。但基本原则是相同的

更新:


正如
LukeH
所指出的,这正是
Lazy
所做的(仅限NET4)。如果可能,请使用该方法,而不是编写自己的方法。

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

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

 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);
       }
    }
}

在您的
GetInstance()
方法中,如果您的值为null,那么您为什么不调用CreateInstance呢?如果您的值为null,那么您就可以进行惰性初始化。

在一个经典的单例中,真正的魔法发生在
静态只读
中,它一经使用就创建实例:

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

    private MySingleton() {}

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

}
如果要将参数传递给构造函数,则必须自己实现锁定(请注意,双
If
sandwitch将
lock
):


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

@user691226您是否可以编写一些代码来说明您是如何做到这一点的,我可能有一些指针。你不能这样做,因为GetInstance没有CreateInstance需要的参数。你能确定他需要什么,因为他需要将参数传递给
CreateInstance
函数。这并不能解决所问的问题。如果这些神奇的参数没有传递到GetInstance,那么他从哪里得到这些参数呢?因为没有任何参数传递到GetInstance,所以我认为他们在这一点上是已知的。问题已经解决了这一点:“我的解决方案(不优雅)是有一个CreateInstance()获取参数并构造singleton实例的静态方法。然后,我将使用另一个无参数的静态方法GetInstance(),以获取singleton实例。”感谢您的回复。我想我希望我可能错过了一种完全不同的方法来实现相同的行为,这种行为给了我编译时检查。你已经描述了
Lazy
是如何工作的:@LukeH:谢谢你的提示,我到目前为止还没有使用过这种方法。是的,这是我已经拥有的代码。不幸的是,问题是我是否可以将此行为的运行时强制更改为编译时行为。但这似乎不可能。哦,对不起,我误解了你的问题。但是不,你不能。我认为这或多或少是唯一的方法。。。我从来没有想到过双
if
结构,我花了大约一分钟才理解它。简单而有效。这是一个完全无用的构造,因为如果单例实例getter总是传递“Something”(或其他一些内部定义的值),那么
myArg
就不是一个参数-至少对使用者来说不是这样-所以实际上这个类仍然有一个无参数的构造函数
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;
        }
    }

}