C# 带参数的单态
我需要用一些参数实例化一个单例类。我现在的做法是:C# 带参数的单态,c#,design-patterns,parameters,singleton,arguments,C#,Design Patterns,Parameters,Singleton,Arguments,我需要用一些参数实例化一个单例类。我现在的做法是: class SingletonExample { private SingletonExample mInstance; //other members... private SingletonExample() { } public SingletonExample Instance { get { if
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...
}
}
实例是“迟创建”的,这意味着我没有应用程序启动时所需的所有参数
一般来说,我不喜欢强制对方法调用进行排序,但我看不到其他方法。IoC也不会解决这个问题,因为我可以在容器中注册它,我也可以调用Create()
你认为这是个好方案吗?你还有别的想法吗
编辑:我知道我所写的示例不是线程安全的,线程安全不是问题的一部分我实际上在你的代码中看不到一个单例。 使用一个静态的、参数化的getInstance方法,该方法返回singleton,如果以前没有使用过它,则创建它。更好的答案:
ISingleton
(包含您希望它执行的任何操作)Singleton:ISingleton
IUnityContainer\u singletonContainer=new UnityContainer();//或初始化容器的任何代码
\u singletonContainer.RegisterType(typeof(ISingleton),newsingleton(params))代码>
如果您想获得singleton,只需使用:
var localSingletonVar=_singletonContainer.Resolve()代码>
注意:如果容器没有为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容器支持对未注册的类型抛出异常,我也会这样做
收件人:非线程安全代码:)带有参数的单例对我来说很可疑
考虑一下特瓦的答案和以下代码:
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);
}
}
在多线程环境中,添加同步以避免竞争条件。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;
}
}
斯基特在几年前写过这篇博客,我认为,这是相当可靠的。没有例外的必要,你不需要记住什么样的对象应该是单态的,当你搞错的时候处理它的影响
编辑:类型与您想要的用途无关,对象仅为方便起见在此处使用。annakata提供的双锁单例解决方案不会每次在所有平台上都有效。这种方法有一个缺陷,这是有充分记录的。不要使用这种方法,否则最终会出现问题
解决此问题的唯一方法是使用volatile关键字,例如
private static volatile Singleton m_instance = null;
这是唯一的线程安全方法。如果您使用的是.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; } }
}
公共密封类单例
{
私有静态只读惰性=
新的Lazy(()=>newsingleton(),LazyThreadSafetyMode.ExecutionAndPublication);
私有单例(){}
公共静态单例实例{get{return lazy.Value;}}
}
///具有双重检查模式和实例参数的通用单例
///
公共类SingleObject,其中T:class,new()
{
///锁定对象
私有静态只读对象_lockingObject=新对象();
///实例
私有静态T_singleObject;
///受保护导体
受保护的SingleObject()
{
}
///带参数的实例
///参数
///实例
公共静态T实例(params dynamic[]param)
{
如果(_singleObject==null)
{
锁定(锁定对象)
{
如果(_singleObject==null)
{
_singleObject=(T)Activator.CreateInstance(typeof(T),param);
}
}
}
返回_singleObject;
}
}
这不是单身汉。互斥在哪里?(即锁
)。加上实例的getter
应该是创建实例,而不是创建ctor——这就是重点。我同意RPM1984,这不是一个单例。您的参数是否可以更改,或者在应用程序的整个生命周期中它们是否相同?单例不应该依赖于某个变量,它可以依赖于配置或另一个单例。然而,仔细想想你的设计,问问自己你是否需要一个单身汉。过度使用单例对你的设计来说真的很糟糕。它是单例的,相信我:)getter不能创建实例,因为它没有参数-它可以有参数,但是这样写更方便。而且,参数一旦获得就不会改变。参数从何而来?@mastoj-来自某个服务调用-它是半静态数据,在我调用它之后是静态的。现在,这是一个单例,不是我显式地使用它们(我让DI来做,并且只用于日志记录之类的事情)+1我会继续假设特瓦决定否决的是一个功能正确的答案。不,他没有(看他的个人资料)。不管怎么说,这些关于单身汉的谈话让我昏昏欲睡,我要去睡觉了谈论修复你的代码。。。天哪,这是马车。为您修复了它。T1,T2不是泛型,只是真实类型的代理。-1我不同意这个解决方案,因为我认为您建议在不应该使用is的地方使用单例模式。单身汉是一个只有
/// <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;
}
}