带参数的单身人士

我需要一个单例类来实例化一些参数。 我现在这样做的方式是:

class SingletonExample { private SingletonExample mInstance; //other members... private SingletonExample() { } public SingletonExample Instance { get { if (mInstance == null) { throw new Exception("Object not created"); } return mInstance; } } public void Create(string arg1, string arg2) { mInstance = new SingletonExample(); mInstance.Arg1 = arg1; mInstance.ObjectCaller = new ObjectCaller(arg2); //etc... basically, create object... } } 

该实例是“迟到”创建的,这意味着我没有在app启动时获得所有必需的参数。

一般来说,我不喜欢强制方法调用的排序,但我没有看到另一种方法。 IoC也不会解决它,因为我可以在容器中注册它,我也可以调用Create()…

你认为这是一个好的方案吗? 你有其他想法吗?

编辑 :我知道我写的是一个例子,它不是线程安全的,线程安全不是问题的一部分

一个带参数的单身人士对我来说有点腥味。

考虑whateva的答案和以下代码:

 Singleton x = Singleton.getInstance("hello", "world"); Singleton y = Singleton.getInstance("foo", "bar"); 

显然,x == y和y与x的创建参数一起使用,而y的创建参数则被忽略。 结果可能至少令人困惑。

如果你真的,真的像你必须这样做,那就这样做:

 class SingletonExample { private static SingletonExample mInstance; //other members... private SingletonExample() { // never used throw new Exception("WTF, who called this constructor?!?"); } private SingletonExample(string arg1, string arg2) { mInstance.Arg1 = arg1; mInstance.ObjectCaller = new ObjectCaller(arg2); //etc... basically, create object... } public static SingletonExample Instance { get { if (mInstance == null) { throw new Exception("Object not created"); } return mInstance; } } public static void Create(string arg1, string arg2) { if (mInstance != null) { throw new Exception("Object already created"); } mInstance = new SingletonExample(arg1, arg2); } } 

在multithreading环境中,添加同步以避免竞争条件。

Singleton是丑陋的,但因为用户whateva不能纠正他自己的代码…

 public class Singleton { private static Singleton _instance = null; private static Object _mutex = new Object(); private Singleton(object arg1, object arg2) { // whatever } public static Singleton GetInstance(object arg1, object arg2) { if (_instance == null) { lock (_mutex) // now I can claim some form of thread safety... { if (_instance == null) { _instance = new Singleton(arg1, arg2); } } } return _instance; } } 

Skeet在几年前发表了博客,我认为,它非常可靠。 没有必要的例外,你不会记住什么对象应该是单身,并在你弄错时处理后果。

编辑:类型不相关使用你想要的东西,这里只是为了方便使用object

更好的答案:

  1. 创建一个接口: ISingleton (包含你想要它做的任何动作)

  2. 你的类型: Singleton : ISingleton

  3. 假设您可以访问UnityContainer:

IUnityContainer _singletonContainer = new UnityContainer(); // or whatever code to initialize the container

  1. 当您准备创建类型使用时(假设您使用Unity for DI):

_singletonContainer.RegisterType(typeof(ISingleton), new Singleton(params));

  1. 如果你想抓住单身人士只需使用:

var localSingletonVar = _singletonContainer.Resolve();

注意:如果容器没有为ISingleton接口注册的类型,那么它应该抛出exception,或者返回null。

旧答案:

 public class Singleton { private static Singleton instance = null; private Singleton(String arg1, String arg2) { } public static Singleton getInstance(String arg1, String arg2) { if (instance != null) { throw new InvalidOperationException("Singleton already created - use getinstance()"); } instance = new Singleton(arg1, arg2); return instance; } public static Singleton getInstance() { if (instance == null) throw new InvalidOperationException("Singleton not created - use GetInstance(arg1, arg2)"); return instance; } } 

我会使用类似的东西(你可能需要检查是否也创建了实例),或者,如果你的DI容器支持在非注册类型上抛出exception,我会继续使用它。

ATTN:非线程安全代码:)

annakata提供的双锁单例解决方案不会在所有平台上每次都有效。 这种方法存在一个缺陷,有很好的记录。 不要使用这种方法,否则你最终会遇到问题。

解决此问题的唯一方法是使用volatile关键字,例如

 private static volatile Singleton m_instance = null; 

这是唯一的线程安全方法。

如果您使用的是.NET 4(或更高版本),则可以使用System.Lazy类型。 它会照顾你的线程安全问题并且做得很懒,所以你不会不必要地创建实例。 这样代码简洁干净。

 public sealed class Singleton { private static readonly Lazy lazy = new Lazy(() => new Singleton(),LazyThreadSafetyMode.ExecutionAndPublication); private Singleton() { } public static Singleton Instance { get { return lazy.Value; } } } 

我实际上在代码中看不到单例。 使用静态的参数化getInstance方法,该方法返回单例并在之前未使用时创建它。

 ///  Generic singleton with double check pattern and with instance parameter  ///  public class SingleObject where T : class, new() { ///  Lock object  private static readonly object _lockingObject = new object(); ///  Instance  private static T _singleObject; ///  Protected ctor  protected SingleObject() { } ///  Instance with parameter  /// Parameters /// Instance public static T Instance(params dynamic[] param) { if (_singleObject == null) { lock (_lockingObject) { if (_singleObject == null) { _singleObject = (T)Activator.CreateInstance(typeof(T), param); } } } return _singleObject; } }