C# 静态内部类单例模式-静态变量何时初始化

article/2025/9/17 19:34:11

对于一个类的静态变量何时初始化,大家都有一个普遍的共识,那就是第一次使用该类时,初始化该类的所有静态变量和静态方法。

    /// <summary>/// 只有在第一次使用到Test1的时候,才会初始化Test1.x/// </summary>class Test1{public static string x = EchoAndReturn("In type initializer");public static string EchoAndReturn(string s){Console.WriteLine(s);return s;}}

但是当我看到单例模式的时候,却看到一个矛盾,那就是饿汉模式下的单例模式,不是懒加载。

    /// <summary>/// 饿汉单例模式,无论是否调用,都会占用系统资源/// </summary>public class HungrySingleton{private static HungrySingleton instance = new HungrySingleton();private HungrySingleton(){}public static HungrySingleton getInstance(){return instance;}}

带着这个疑问,我继续探究下去,到网上查到了基于静态内部类的单例模式。网上的说法是,该方式能够实现延迟加载。

public class Singleton6
{
private Singleton6() { }private static class SingletonInstance
{public static Singleton6 Instance = new Singleton6();
}public static Singleton6 Instance()
{return SingletonInstance.Instance;
}
}

如果说静态成员是在类第一次被使用时进行初始化,那饿汉模式和静态内部类的方式并没有区别,都会实现延迟加载。

带着这个疑问,我进行了实验,发现了一个神奇的现象

    class Program{static void Main(string[] args){Console.WriteLine("Starting Main");Test1.EchoAndReturn("Echo!");Console.WriteLine("After echo");//Reference a static field in Teststring y = Test1.x;//Use the value just to avoid compiler clevernessif (y != null){Console.WriteLine("After field access");}Console.ReadKey();}}/// <summary>/// 理论上只有在第一次使用到Test1的时候,才会初始化Test1.x/// 也就是In type initializer出现在Starting Main之后/// </summary>class Test1{public static string x = EchoAndReturn("In type initializer");public static string EchoAndReturn(string s){Console.WriteLine(s);return s;}}

这里写图片描述

按理来说,In type initializer这句话应该是在Starting Main之后才会出现,却出现在了最前面,难道说静态成员不是在类第一次被使用时进行初始化,而是在程序启动时就初始化?

查阅了相关资料之后,终于找到了问题的答案,那就是类都有一个隐藏属性beforefieldinit。

beforefieldinit,JIT编译器可以在首次访问一个静态字段或者一个静态/实例方法之前,或者创建类型的第一个实例之前,随便找一个时间生成调用。具体调用时机由CLR决定,它只保证访问成员之前会执行(隐式)静态构造函数,但可能会提前很早就执行。

也就是说静态成员会在类第一次使用之前的任何时间初始化(由CLR智能决定),如果是这样的话,静态内部类的方式岂不是解决不了延迟加载的问题?

有办法,那就是在类中实现静态构造函数,那beforefieldinit属性就会被precise属性替换,确保静态成员会在类第一次使用之前的那一刻进行初始化。

    class Program{static void Main(string[] args){Console.WriteLine("Starting Main");Test2.EchoAndReturn("Echo!");Console.WriteLine("After echo");//Reference a static field in Teststring y = Test2.x;//Use the value just to avoid compiler clevernessif (y != null){Console.WriteLine("After field access");}Console.ReadKey();}}/// <summary>/// 只有在第一次使用到Test1的时候,才会初始化Test1.x/// </summary>class Test1{public static string x = EchoAndReturn("In type initializer");public static string EchoAndReturn(string s){Console.WriteLine(s);return s;}}class Test2{public static string x = EchoAndReturn("In type initializer");// Defines a parameterless constructor.static Test2(){}public static string EchoAndReturn(string s){Console.WriteLine(s);return s;}}

这里写图片描述

按照这种方式确实解决了静态成员在类第一次使用之前的那一刻进行初始化的问题。但是网上能够找到的静态内部类单例模式普遍都有一个问题,那就是没有实现静态内部类的静态构造函数,结果就是和饿汉模式一样,没有解决延迟加载问题,最后贴上正确的静态内部类单例模式

/// <summary>/// 静态内部类单例模式,线程安全/// </summary>public class StaticSingleton{private class InnerInstance{/// <summary>/// 当一个类有静态构造函数时,它的静态成员变量不会被beforefieldinit修饰/// 就会确保在被引用的时候才会实例化,而不是程序启动的时候实例化/// </summary>static InnerInstance() { }internal static StaticSingleton instance = new StaticSingleton();}private StaticSingleton(){}public static StaticSingleton getInstance(){return InnerInstance.instance;}}

http://chatgpt.dhexx.cn/article/Rx10X1xe.shtml

相关文章

静态内部类实现单例_单例模式详解

概述 单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,使用单例模式的类只有一个对象实例。 单例应用场景 Windows系统的任务管理器。Windows系统的回收站。操作系统的文件系统,一个操作系统只能有一个文件系…

使用静态内部类单例模式创建自定义线程池

一、使用场景 1、有时候业务上A端和B端做接口传输消息&#xff0c;B端收到消息后做进一步数据处理&#xff08;持久化或者解析&#xff09;等耗时的操作&#xff0c;如果是同步操作会造成等待、超时等情况。可以先向A端返回一个收到信息的消息&#xff0c;再多线程异步处理数据…

Kotlin 静态内部类单例模式的正确实现方式

本篇是对现网上流传的 Kotlin 实现静态内部类单例模式的纠正&#xff0c;为了把原理说清楚&#xff0c;文章前奏可能会有些长&#xff0c;熟悉静态内部类单例模式原理的朋友&#xff0c;可以直接跳转到文章最后&#xff0c;直接看结果即可。 最近在整理基础库的时候&#xff0c…

设计模式3:单例模式:静态内部类单例模式

单例模式最简单的写法就是静态内部类单例模式&#xff0c;如下&#xff1a; public class Manager {private static class ManagerHolder {private static Manager instance new Manager();}private Manager() {}public static Manager getInstance() {return ManagerHolder.i…

单例模式详解

微信搜索【程序员囧辉】&#xff0c;关注这个坚持分享技术干货的程序员。 概述 单例模式&#xff0c;是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中&#xff0c;使用单例模式的类只有一个对象实例。 单例应用场景 Wi…

MATLAB中的结构体数组(struct)学习笔记

不要失却热情&#xff0c;不要丢掉冠军的心&#xff01; MALAB中的结构体&#xff08;struct&#xff09;数组学习笔记 前言1. 版本2. 关键词 一、Struct结构体数组概述二、Struct结构体数组基本用法1. 结构体的创建2. 结构体中的筛选操作 前言 MATLAB中结构体数组基本用法笔…

MATLAB学习——结构体类型

前言 MATLAB 中的数据类型主要包括数值类型、 逻辑类型、 字符串、函数句柄、 结构体和单元数组类型。 这6种基本的数据类型都是按照数组形式存储和操作的。 一、结构体类型 MATLAB中的结构体与C语言中的结构体类似&#xff0c; 一个结构体可以通过字段存储多个不同类型的数…

Matlab将结构体struct字段内的数据转化到矩阵中

假设structure1,为一结构体&#xff0c;structure1.name为100个字符串 怎么将这些字符串不用循环一次性赋值到矩阵A?? Astructure1.name 为什么只是将第一个赋值过去&#xff1f; 答案是可以使用cat函数&#xff1a; 可以用cat函数&#xff0c; A cat(1,structur1.name)是…

Matlab:结构体数组

Matlab:结构体数组 创建标量结构体访问字段中的值对非标量结构体数组进行索引当您有要按名称组织的数据时,可以使用结构体来存储这些数据。结构体将数据存储在名为字段的容器中,然后您可以按指定的名称访问这些字段。使用圆点表示法创建、分配和访问结构体字段中的数据。如果…

Matlab-结构数组

1 认识结构数组 结构也是一种数据类型&#xff0c;它的每一个元素都有一个名字。称结构中的元素为域。 类似与C语言中的结构体。 2 创建 两种方法&#xff1a; &#xff08;1&#xff09;用赋值语句创建 &#xff08;2&#xff09;用函数 struct 函数进行创建 2.1 赋值语…

Matlab遇到结构体内容引用自非结构体数组对象

原因&#xff1a; 未初始化下一级结构体的值&#xff0c;如果直接调用就会报错。 举例&#xff1a; a.p[]; a.p.x解决方法&#xff1a; 需要先初始化&#xff0c;再调用 a.p.x[] or a.p.x0

Matlab:结构体Struct

Matlab中创建一个结构体数组的方式有两种&#xff0c;分别为直接引用方式和使用struct函数。 1、使用直接引用方式创建结构体 与建立数值型数组一样&#xff0c;建立新struct对象不需要事先申明&#xff0c;可以直接引用&#xff0c;而且可以动态扩充。比如建立一个复数变量x…

Matlab 结构体(struct)使用

转自http://blog.sina.com.cn/s/blog_468651400100c6c0.html 要在MALTAB中实现比较复杂的编程&#xff0c;就不能不用struct类型。而且在 MATLAB中实现struct比C中更为方便。 4. 3.1 结构数组的创建 MATLAB提供了两种定义结构的方式&#xff1a;直接应用和使用struct函数。 1. …

MATALB-结构体

结构体 结构体的生成一、 直接输入二、使用结构体生成函数struct 结构体的操作添加成员变量删除成员变量调用成员变量 结构体是另一种可以将不同类型数据组合在一起的数据类型。 MATLAB结构体变量类似于C语言结构体变量,且比C语音更加直观。 结构体与单元数组的区别为,结构体…

matlab学习-结构体变量

matlab结构体学习 matlab结构体学习 matlab结构体与C语言数据结构结构体或java语言类的定义有异曲同工之妙&#xff0c;其主要知识点如下 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 matlab结构体学习前言一…

matlab-结构体struct

在前面&#xff0c;有用到一个cell2struct&#xff08;&#xff09;函数&#xff0c;cell是单元数组&#xff0c;而struct就是结构体。 1.建立结构体&#xff0c;在matlab中建立结构体有两种方式&#xff0c; eg&#xff1a;第一种为直接赋值 >> stu(1).namezhangsan;…

matlab中结构体使用方法

转自 http://hi.baidu.com/dess2211/blog/item/bb9b80185a7f940334fa417c.html matlab中使用结构体 2008-01-15 14:23 结构(struct)数组 要在MALTAB中实现比较复杂的编程&#xff0c;就不能不用struct类型。而且在 MATLAB中实现struct比C中更为方便。 4. 3.1 结构数组的创建 MA…

Matlab中结构体struct创建和使用

在项目上遇见了调用api接口&#xff0c;接口返回的信息为struct&#xff0c;故探讨一下matlab的struct结构体 1、struct结构体创建 创建结构体数组有两种方式&#xff0c;分别为直接创建和使用struct函数 1.1 直接创建 直接定义字段&#xff0c;像使用一般matlab变量一样&…

matlab 结构体

在前面&#xff0c;有用到一个cell2struct&#xff08;&#xff09;函数&#xff0c;cell是单元数组&#xff0c;而struct就是结构体。 1.建立结构体&#xff0c;在matlab中建立结构体有两种方式&#xff0c; eg&#xff1a;第一种为直接赋值 >> stu(1).namezhangsan; …

单片机实例4——广告灯的左移右移(硬件电路图+汇编程序+C语言程序)

4&#xff0e; 广告灯的左移右移 1&#xff0e; 实验任务 做单一灯的左移右移&#xff0c;硬件电路如图4.4.1所示&#xff0c;八个发光二极管L1&#xff0d;L8分别接在单片机的P1.0&#xff0d;P1.7接口上&#xff0c;输出“0”时&#xff0c;发光二极管亮&#xff0c;开始时P…