我需要使用一些参数来实例化单例类。我现在这样做的方式是:
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()......
你认为这是一个好的方案吗?你有其他想法吗?
编辑:我知道我写的是一个例子,它不是线程安全的,线程安全不是问题的一部分
答案 0 :(得分:32)
单身人士很难看,但因为用户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 :(得分:22)
一个带有参数的单身人士对我来说有点腥味。
考虑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);
}
}
在多线程环境中,添加同步以避免竞争条件。
答案 2 :(得分:6)
更好的回答:
创建一个界面:ISingleton
(包含您希望它执行的任何操作)
您的类型:Singleton : ISingleton
假设您有权访问UnityContainer:
IUnityContainer _singletonContainer = new UnityContainer(); // or whatever code to initialize the container
_singletonContainer.RegisterType(typeof(ISingleton), new Singleton(params));
var localSingletonVar = _singletonContainer.Resolve<ISingleton>();
注意:如果容器没有为ISingleton接口注册的类型,那么它应该抛出异常,或者返回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容器支持在非注册类型上抛出异常,我会继续使用它。
ATTN:非线程安全代码:)
答案 3 :(得分:2)
annakata提供的双锁单例解决方案不会在所有平台上每次都有效。这种方法存在一个缺陷,有很好的记录。不要使用这种方法,否则你最终会遇到问题。
解决此问题的唯一方法是使用volatile关键字,例如
private static volatile Singleton m_instance = null;
这是唯一的线程安全方法。
答案 4 :(得分:1)
如果您使用的是.NET 4(或更高版本),则可以使用System.Lazy类型。 它会照顾你的线程安全问题并且做得很懒,所以你不会不必要地创建实例。 这样代码简洁干净。
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy =
new Lazy<Singleton>(() => new Singleton(),LazyThreadSafetyMode.ExecutionAndPublication);
private Singleton() { }
public static Singleton Instance { get { return lazy.Value; } }
}
答案 5 :(得分:0)
我实际上在代码中看不到单例。 使用静态的参数化getInstance方法,该方法返回单例并在之前未使用时创建它。
答案 6 :(得分:0)
/// <summary> Generic singleton with double check pattern and with instance parameter </summary>
/// <typeparam name="T"></typeparam>
public class SingleObject<T> where T : class, new()
{
/// <summary> Lock object </summary>
private static readonly object _lockingObject = new object();
/// <summary> Instance </summary>
private static T _singleObject;
/// <summary> Protected ctor </summary>
protected SingleObject()
{
}
/// <summary> Instance with parameter </summary>
/// <param name="param">Parameters</param>
/// <returns>Instance</returns>
public static T Instance(params dynamic[] param)
{
if (_singleObject == null)
{
lock (_lockingObject)
{
if (_singleObject == null)
{
_singleObject = (T)Activator.CreateInstance(typeof(T), param);
}
}
}
return _singleObject;
}
}