单例模式中的空值检查有什么用处?

3
在单例模式中,我们有一个私有构造函数和一个公共静态方法,如下所示 -
public class MyClass
{
     private static MyClass _uniqueInstance;

     private MyClass()
     { 
     }

     public static MyClass GetInstance()
     {
         if(_uniqueInstance==null)
         { 
             _uniqueInstance = new MyClass();
         }
         return _uniqueInstance;
     }
}

当我们需要该类的对象时,可以通过调用静态方法来创建此类的唯一实例 -

var myObject = MyClass.GetInstance();

但是我很困惑为什么我们在GetInstance()方法中检查null,因为"_uniqueInstance"已经是一个静态变量,所以它只会被初始化和分配内存一次。即使我们不检查null并使用"new"初始化对象,由于它是一个静态变量,内存也不会再次分配给这个对象。那么,这个null检查有什么用呢?请帮我解惑。


1
检查的目的是使代码更难理解,并在多线程环境中引入问题。请参阅Jon Skeet的文章 - http://csharpindepth.com/Articles/General/Singleton.aspx - Alexei Levenkov
4个回答

4

我是一名有用的助手,可以翻译文本。

我感到在初始化器、工厂和单例之间存在混淆。

字段初始化器:

static readonly object Value = new object();

一个工厂方法:
static object CreateValue()
{
    return new object();
}

单例模式:

static object _value;

static object Value
{
    get
    {
        return _value ?? (_value = new object());
    }
}

编译时,初始化程序被移除到静态构造函数中,该函数只运行一次,就像您猜想的那样。除了顺序外,静态字段的初始化是不可控的。当任何静态字段初始化时,所有静态字段都会初始化。单例模式可以防止这种情况。

工厂方法旨在抽象出实例构造函数

单例模式可以被认为是字段初始化器的抽象,确保资源直到必要时才被引入。然而,对于最有可能被引用的资源,如String.Empty,最好使用静态字段来避免混乱。


3
如果您使用以下代码:
public static MyClass GetInstance()
{
    _uniqueInstance = new MyClass();
    return _uniqueInstance;
}

每次调用GetInstance时,您将获得该类的不同实例,这与Singleton的概念相矛盾。 Singleton模式的想法是始终获得该类的相同实例,无论在应用程序中调用多少次。并且只应构造此实例一次。
因此,基本上,空值检查仅在第一次调用GetInstance时返回true,以实例化私有静态字段(默认情况下为null),并且在后续调用中将返回相同的实例。
请注意,您显示的此单例模式实现不是线程安全的。如果2个线程同时在开头调用GetInstance方法,则可能会获得2个不同的实例。
您可以在this article中了解有关Singleton模式和各种C#实现的更多信息。

1
我们使用单例模式来获取一个对象的唯一实例,并在各处使用此实例。
如果我们删除空值检查if(_uniqueInstance==null),那么每次调用GetInstance时都会创建一个新实例,并将其存储在_uniqueInstance变量中。
即使我们不检查null并仍然使用“new”初始化对象,由于它是静态变量,因此不会再为该对象分配内存。
由于_uniqueInstance是静态的引用类型,因此只会为其分配一次内存。但是您可以将许多引用分配给此静态变量,并且这些对象可以根据需要在内存中创建多次。
那么,这个空值检查有什么用呢?
空值检查确保_uniqueInstance只分配了一个MyClass实例,并且在应用程序域的生命周期内永远不会更改。因此,每个人调用GetInstance都将获得MyClass的相同实例。 阅读有关单例模式的更多信息

0

这是错误的:

即使我们不检查 null 并仍使用 "new" 初始化对象,由于它是静态变量,因此不会为此对象重新分配内存。

调用 new 将分配新的内存,并且 _uniqueInstance 将具有新指针。因此,在每次调用该方法时都会有不同的实例 - 这不是单例模式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接