我花了大约一个小时寻找关于我想要完成的事情的一致意见,但尚未在特定方向找到任何结论。
我的情况如下:
我以前使用的方法是在静态构造函数中构造这些对象。这样做的问题在于,如上所述,构造函数偶尔会失败,并且一旦.NET静态构造函数失败,整个类就被清除,直到重新启动进程。这种方法没有第二次机会。
此后最直观的方法是使用双重检查锁定。有很多关于双重检查锁定的弊端并且说使用静态构造函数的页面,我已经在做了,但这对我来说似乎不是一个选项,因为静态构造函数有可能会失败并使整个班级失望。
我正在考虑使用的实现(当然简化)如下。所有的类和成员名称都是纯粹的示范,而不是我实际使用的。这种方法会有问题吗?有谁能建议更好的方法?
public class LazyMembers
{
private static volatile XmlDocument s_doc;
private static volatile XmlNamespaceManager s_nsmgr;
private static readonly object s_lock = new object();
private static void EnsureStaticMembers()
{
if (s_doc == null || s_nsmgr == null)
{
lock (s_lock)
{
if (s_doc == null || s_nsmgr == null)
{
// The following method might fail
// with an exception, but if it succeeds,
// s_doc and s_nsmgr will be initialized
s_doc = LoadDoc(out s_nsmgr);
}
}
}
}
public XmlNamespaceManager NamespaceManager
{
get
{
EnsureStaticMembers();
return s_nsmgr;
}
}
public XmlDocument GetDocClone()
{
EnsureStaticMembers();
return (XmlDocument)s_doc.Clone();
}
}
答案 0 :(得分:2)
如果使用.NET 4.0,可以参考Lazy<T>
和LazyThreadSafetyMode(这取决于您是否希望在多线程环境中创建或不创建T的实例。在您的情况下,您需要参考Lazy<T>(Func<T> func, LazyThreadSafetyMode
)构造函数 - here(MSDN)
否则(如果使用3.5或更低版本),CAS技术可以创建单个实例而无需锁定。
这样的事情:
get {
if( _instance == null) {
var singleton = new Singleton();
if(Interlocked.CompareExchange(ref _instance, singleton, null) != null) {
if (singleton is IDisposable) singleton.Dispose();
}
}
return _instance;
}
但是,在这里,您只能实现LazyThreadSafetyMode.Publications行为 - 其他线程只能看到一个实例,但很少可以创建。
此外,在代码中对null进行双重检查应该没有任何问题 - 它在.NET世界中是安全的(至少在x86机器和相关的内存模型上)。在2004年之前,Java世界存在一些问题,AFAIK。