Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
“静态类”;初始化";C#中的模式?_C#_Static_Initialization - Fatal编程技术网

“静态类”;初始化";C#中的模式?

“静态类”;初始化";C#中的模式?,c#,static,initialization,C#,Static,Initialization,使用此模式的好处或原因是什么 public sealed class myStaticClass { private static bool _initialized; private static object _lockObject; private static string _someStaticField; private static int _anotherStaticField; private static string _nthSta

使用此模式的好处或原因是什么

public sealed class myStaticClass
{
    private static bool _initialized;
    private static object _lockObject;

    private static string _someStaticField;
    private static int _anotherStaticField;
    private static string _nthStaticField;

    static myStaticClass()
    {
        _initialized = false;  
        _lockObject = new object();
    }

    public myStaticClass()
    {
    }

    public static void Initialize()
    {
        if(!_initialized)
        {
            lock(_lockObject)
            {
                if(!_initialized)
                {
                    //do initializing
                    _someStaticField = someApplicationSetting;
                    _anotherStaticField = anotherApplicationSetting;
                    _nthStaticField = nthApplicationSetting;

                    _initialized = true;
                }
            }
        }
    }

    public static string NthStaticField 
    { 
        get {

            Initialize();
            return _nthOtherField;
        }
    }
}
如果保证在访问任何类成员之前调用静态构造函数,并且只调用一次,那么为什么不将所有初始化逻辑都放在静态构造函数中呢

编辑:我已经更新了模式,以便更好地反映发现该模式的.net framework中的类。我已经将类上的
static
修饰符更改为
sealed
,并且还添加了一个空的
public
构造函数


顺便说一句,如果你想知道,我看到这个模式的类是
FormsAuthentication
类。

这样做的唯一原因是如果初始化很昂贵(就CPU/RAM而言),或者所需的东西只在运行时后期才可用。。。此实现将初始化延迟到可能的最新时刻(第一次访问之前)。这是一种提供的功能…

可能,应用程序设置在运行时稍后才可用。

好的,我现在已经阅读并考虑了给出的链接,并得出结论,这个特定示例没有中断。

我将解释为什么

首先,它与CSharp深入文章中的模式不同。本文中的模式适用于单例。我介绍的模式不是单例模式,它有一个公共构造函数,但是它的所有字段都是静态的。因此,最大的区别在于csharpindepth模式返回对单例对象的引用,即使它实际上可能尚未完全实例化。关键的一点是,在构造函数完成之前,可以将实例分配给引用

public sealed class Singleton
{
 private static Singleton instance = null;
 private static readonly object padlock = new object();

Singleton()
 {
 }

public static Singleton Instance
 {
     get
     {
         if (instance == null)
         {
             lock (padlock)
             {
                 if (instance == null)
                 {
                     instance = new Singleton();
                 }
             }
         }
         return instance;
     }
 }
} 
这是csharpindepth模式,其工作原理如下

如果有3个线程A、B和C。线程A调用Instance方法,Instance为null,则获取锁。现在,在线程A创建Sigleton实例之前,线程B的实例仍然为空。但是A有锁,所以B等待。当B在等待时,线程A执行代码
instance=newinstance()
。此时,instance被设置为Singleton的一个实例,但是它可能还没有实际构建这就是线程安全性中断的地方。线程C出现时,它看到实例不是null,因此实例方法返回对实例的引用但是线程A尚未完成实例的构造,因此线程C和与线程C同时进入的任何其他线程都会获得对一个dud单例实例的引用。最后A完成了,B得到了锁,但是工作现在完成了,所以它退出了

我介绍的模式有很大不同。用于双重检查的字段不是在Initialize方法中创建的实例。它是一个简单的
专用静态bool
,用作开关。由于它不是对尚待构造的单例对象的引用,并且从未在该类之外访问过它,所以没有问题


如果在初始化类字段之前,在顶部将
private static bool\u initialized
开关设置为true,则会出现问题。这是代码放弃锁之前发生的最后一件事。因此,线程C不可能读取
\u initialized
,并将类误认为已初始化。因此,无论如何boken都不会这样做。

查找C#的“双重检查锁定”和/或“惰性初始化”。在几篇文章中有一篇很好的文章链接到,讨论了获得这种惰性(需要时一次)初始化的不同方法。(在许多情况下,发布的代码实际上不是推荐的方法之一;-)啊,这里是C#Depth的著名文章:列出了5种方法,并给出了解释@pst是正确的,但应该更加有力。这个代码被严重破坏和错误。你不能像这样安全地进行双重检查锁定!双重检查锁定的基本规则是,您测试的东西必须是您唯一变异的东西。您不能使用标志来控制双重检查锁定,然后完全改变其他变量;那绝对不能保证安全。如果您不完全了解运行时的内存模型,则不应尝试编写低锁代码;这是另一个著名的“危险破坏的错误实现的双重检查锁定模式”的例子。