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

我正在为我的一个项目实现一个通知框架。 由于我希望它非常通用,用户可以使用多个传输层,因此他并不需要关心使用一种传递方法(比方说WCF)或另一种(例如ActiveMQ)。 用户可以访问的界面当然与传递方法(WCF或ActiveMQ)无关。 尽管如此,这两个类(使用者和生产者)实现了单例,因此它们实际上使用默认构造函数(意思是没有参数)。 我的问题是,我想有一个参数,用户想要使用的交付方法。 但据我所知,单身人士只使用默认构造函数? 这是正常的,因为没有必要使用带参数的单例。 那么,我的选择是什么? 不创造单身人士? 创建一个设置交付方式的方法?

非常感谢您的帮助,

塞巴斯蒂安

你当然可以使用单例参数,除了不将参数传递给构造函数,而是将它传递给getInstance()方法。 您的被覆盖的构造函数当然需要是私有的,才能实现真正的单例实现。 我的例子是用Java编写的,但也适用于C#。

例:

Singleton s = Singleton.getInstance(42); 

在Singleton代码中:

 private Singleton() { } private Singleton(int num) { //set num } public getInstance(int num) { //singleton code (calls the private non-default constructor if an object //does not already exist) } 

有一些dependency injection框架,如Spring.Net,可能会对你有所帮助。 您可以在单例构造函数的配置文件中有效地传递参数。

链接到Spring Framework示例

我可能会建议,如果您的单身人员需要两种不同的行为,那么您可能想要进行子类化。 这样,您可以通过调用所需类行为的单例来获得所需的行为。

您可以使用dependency injection框架轻松完成此操作。 我在使用MEF的当前项目中有类似的构造。 所需要的只是使用构造函数注入选项,并将该程序集和请求的依赖项程序集添加到目录中,并将其正确连接。

另一种选择是使用某种forms的初始化函数来获取您的选项,并构造单例实例。 您可以在初始化调用期间构造它,而不是在第一次访问时构造它。 这里的缺点是你需要确保在使用它之前初始化你的单例(通常在程序启动时,使用配置文件)。

一个类似但不易出错的选项是让单例延迟初始化,并给它一个“默认”选项。 允许调用者设置静态属性以改变构造哪个选项,因此如果在单例构造之前设置它,则会得到不同的默认值。 但是,这可能令人困惑,因为再次,您需要确保在访问单例之前设置属性,否则您将获得意外行为。

我知道回答原始问题已经很晚了,但我刚遇到这个问题,这就是我如何解决它的问题。 可能不理想,但似乎有效。 我创建了一个必须在尝试使用单例实例之前调用的Init方法。

 public void Init(/*parameters*/) { if (_isInitialized) { throw new InvalidOperationException("Component is already initialized!"); } //do your work here } 

对单例实例的任何其他访问(属性get,set,方法调用)都将抛出一个无效的操作exception,告知该对象未被初始化。

我认为这样做我需要的,比GetInstance(params)更容易混淆,因为没有误解方法的作用的风险。 缺点是它不会抛出编译时错误,但没有初始化完成的第一次运行会抛出exception,所以它应该足够好了。