关于c#:在Singleton模式中使用null检查有什么用?

What is the use of null checking in Singleton pattern?

在单例模式中,我们有一个私有的构造函数和一个公共的静态方法,如下所示-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyClass
{
     private static MyClass _uniqueInstance;

     private MyClass()
     {
     }

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

我们可以通过调用静态方法来创建这个类的一个并且只有一个实例,只要我们需要这个类的对象,比如-

1
var myObject = MyClass.GetInstance();

但是我很困惑为什么我们在getInstance()方法中检查空值,因为"UniqueInstance"已经是一个静态变量,所以它将被初始化并只分配一次内存。即使我们不检查空值并且仍然用"new"初始化对象,也不会为这个对象再次分配内存,因为它是一个静态变量。那么,这个空检查的用途是什么呢?请澄清我的疑虑。


如果使用以下代码:

1
2
3
4
5
public static MyClass GetInstance()
{
    _uniqueInstance = new MyClass();
    return _uniqueInstance;
}

然后,每当有人调用这个GetInstance,你就会得到一个与单例程序不同的类实例。单例模式的思想是始终获取类的相同实例,无论在应用程序中调用它多少次。这个实例应该只构造一次。

因此,基本上只有在第一次调用GetInstance以实例化私有静态字段(默认为空)时,空检查才会返回true,并且在随后的调用中,将返回相同的实例。

尽管您在这里展示的这个单例模式实现不是线程安全的。如果两个线程同时在开始时调用GetInstance方法,它们可能会得到两个不同的实例。

您可以阅读更多关于单例模式和this article中各种C实现的信息。


我感觉到初始值设定项、工厂和单例之间的混淆。

字段初始值设定项:

1
static readonly object Value = new object();

工厂方法:

1
2
3
4
static object CreateValue()
{
    return new object();
}

单子模式:

1
2
3
4
5
6
7
8
9
static object _value;

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

初始值设定项在编译时被移除到静态构造函数中,该构造函数会像您所猜测的那样运行一次。除了顺序之外,静态字段的初始化是不可控制的。当任何静态字段初始化时,则所有静态字段初始化。单子模式阻止了这一点。

工厂方法旨在作为实例构造函数的抽象。

可以将单例模式视为字段初始值设定项的抽象,从而确保在必要时才引入资源。但是,对于最确定引用的资源,如String.Empty,最好使用静态字段来避免混乱。


我们使用singleton模式只获取对象的一个实例,并且在任何地方都使用这个实例。

如果删除空检查if(_uniqueInstance==null),那么每次调用GetInstance时都会创建一个新实例,并将其存储在_uniqueInstance变量中。

Even if we do not check for null and still initialize the object with
"new", memory will not be allocated again for this object as it is a
static variable.

内存作为引用类型分配给_uniqueInstance,只分配一次,因为它是静态的。但是您可以为这个静态变量分配许多引用,并且可以根据需要在内存中创建尽可能多的对象。

So, what is the use of this null check

空检查确保_uniqueInstance只与MyClass的一个实例分配一次,并且在应用程序域的生命周期内不会改变。所以每个调用GetInstance的人都会得到相同的MyClass实例。

阅读有关singleton的更多信息


这是错误的:

Even if we do not check for null and still initialize the object with
"new", memory will not be allocated again for this object as it is a
static variable.

调用new将分配新内存,_uniqueInstance将有一个新指针。所以,对方法的每个调用都有不同的实例-它不是单例的。