静态构造函数和非静态构造函数

本文深入解析静态构造函数的特点和调用时机,阐述其与普通构造函数的区别,以及在.NET框架中的应用。通过代码示例,展示静态构造函数如何初始化静态成员变量,强调其在类实例化或静态成员调用时由框架自动调用的特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

静态构造函数是在构造函数方法前面添加了static关键字之后形成的,并且没有修饰符(public,private),没有参数。

特点:

1、静态构造函数没有修饰符修饰(public,private),因为静态构造函数不是我们程序员调用的,是由.net 框架在合适的时机调用的。
2、静态构造函数没有参数,因为框架不可能知道我们需要在函数中添加什么参数,所以规定不能使用参数。
3、静态构造函数前面必须是static 关键字。如果不加这个关键字,那就是普通的构造函数了。
4、静态构造函数中不能实例化实例变量。(变量可以分为类级别和实例级别的变量,其中类级别的有static关键字修饰)。
5、静态函数的调用时机,是在类被实例化或者静态成员被调用的时候进行调用,并且是由.net框架来调用静态构造函数来初始化静态成员变量。
6、一个类中只能有一个静态构造函数。
7、无参数的静态构造函数和无参数的构造函数是可以并存的。因为他们一个属于类级别,一个属于实例级别,并不冲突。
8、静态构造函数只会被执行一次。并且是在特点5中的调用时机中进行调用。
9、如果没有在类中写构造函数,那么框架会为我们生成一个构造函数,那么如果我们在类中定义了静态变量,但是又没有定义静态构造函数,那么框架也会帮助我们来生成一个静态构造函数来让框架自身来调用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class A
    {
        static A()
        {
            Console.WriteLine("1");
        }
        public A()
        {
            Console.WriteLine("2");

        }
    }
    class B : A
    {
        static B()
        {
            Console.WriteLine("a");
        }
        public B()
        {
            Console.WriteLine("b");

        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //a 1 2 b
            A ab = new B();
            Console.WriteLine("--------");
            //2 b
            ab = new B();
            Console.ReadKey();
        }
    }
}

执行结果:
在这里插入图片描述

1、A ab = new B();

A. 实例化B, 执行B的静态构造函数 == 输出a
B. 执行B的构造函数,因为B继承自A,所以先进入A
C. 实例化A, 执行A的静态构造函数,== 输出 1
D. 执行A的构造函数 ==输出2
E. 最后回到B的构造函数 == 输出b

2、ab = new B();

因为静态构造函数只创建一次,所以不会进入静态构造函数

A. 因为B继承自A,所以先进入A的构造函数 == 输出2
B. 再进入B的构造函数 == 输出b

<think>嗯,用户现在想了解构造函数静态构造函数的概念及区别。之前他们可能接触过结构体的相关内容,现在转向了面向对象中的构造函数。首先,我需要明确构造函数静态构造函数的基本定义,然后比较它们的区别,再给出使用场景。根据提供的引用,C#中的静态构造函数有一些特点:没有修饰符,没有参数,由框架自动调用,初始化静态成员,只会执行一次。而普通构造函数用于实例对象的初始化。需要将这些信息整理出来,分点说明。用户可能混淆两者的调用时机作用对象。需要强调静态构造函数处理类级别的静态成员,而构造函数处理实例级别的成员。同时,静态构造函数在类第一次被使用前自动调用,而普通构造函数在每次实例化时调用。还要注意代码示例,用C#展示两者的不同写法,比如静态构造函数用static关键字,普通构造函数用类名。同时,引用中的例子StaticClass展示了静态类中的静态构造函数如何初始化静态变量,可以引用作为例子。需要检查是否涵盖了所有区别点:修饰符、参数、调用时机、执行次数、作用对象等。另外,用户可能想知道为什么需要静态构造函数,比如初始化复杂的静态成员或执行一次性的操作。 可能的问题点:用户是否了解静态成员实例成员的区别?是否需要先简要说明这些概念?不过根据用户的问题,他们可能已经有一定基础,所以直接比较即可。 最后生成相关问题时,要考虑与构造函数相关的扩展,比如执行顺序、设计模式中的应用,或者与析构函数的对比。确保问题有针对性,帮助用户深入理解。</think>### 构造函数静态构造函数的区别及用法 #### 一、基本概念对比 | **特性** | **构造函数** | **静态构造函数** | |--------------------|------------------------------------------|---------------------------------------------| | **作用对象** | 实例级别(初始化实例成员变量)[^1] | 类级别(初始化静态成员变量)[^2] | | **修饰符** | 可指定`public`/`private`等访问修饰符 | 无修饰符,仅允许`static`关键字[^1] | | **参数支持** | 支持参数重载(可定义多个不同参数的构造函数) | 禁止使用任何参数[^1] | | **调用时机** | 每次实例化对象时触发 | 类首次被访问(实例化或调用静态成员)时触发[^1] | | **执行次数** | 每个对象实例化时执行一次 | 整个程序生命周期内仅执行一次[^1] | #### 二、语法结构对比 **普通构造函数示例**: ```csharp public class Car { public string Model { get; set; } // 实例构造函数(带参数) public Car(string model) { Model = model; // 初始化实例成员[^1] Console.WriteLine("实例构造函数执行"); } } Car myCar = new Car("Tesla"); // 触发构造函数 ``` **静态构造函数示例**: ```csharp public class Logger { public static string LogPath; // 静态构造函数(无参数) static Logger() { LogPath = "C:/logs/app.log"; // 初始化静态成员[^2] Console.WriteLine("静态构造函数执行"); } } Console.WriteLine(Logger.LogPath); // 首次访问触发静态构造函数 ``` #### 三、核心差异详解 1. **内存管理机制** - 实例构造函数操作**堆内存**中的对象实例 - 静态构造函数初始化**全局内存**中的静态变量(存储在Loader Heap中)[^1] 2. **初始化顺序** - 类加载时:静态字段初始化 → 静态构造函数执行 - 对象实例化时:实例字段初始化 → 实例构造函数执行 $$ \text{执行顺序} = \begin{cases} \text{静态初始化} & \text{首次访问类时} \\ \text{实例初始化} & \text{每次new时} \end{cases} $$ 3. **线程安全性** - 静态构造函数由CLR保证线程安全,避免多线程重复初始化[^1] - 实例构造函数需开发者自行处理线程同步问题 #### 四、典型应用场景 | **场景** | **构造函数用途** | **静态构造函数用途** | |-------------------|------------------------------------------|---------------------------------------------| | 配置初始化 | 设置对象初始状态(如数据库连接参数) | 加载全局配置(如日志路径、加密密钥)[^2] | | 资源预加载 | 创建对象时分配共享资源(如文件句柄) | 预加载共享资源(如缓存数据、静态字典) | | 类型验证 | 验证实例参数合法性 | 验证静态依赖项(如检查必需环境变量) | #### 五、执行流程验证实验 ```csharp public class TestClass { public static int StaticValue; public int InstanceValue; static TestClass() { StaticValue = 100; Console.WriteLine($"静态构造函数设置StaticValue={StaticValue}"); } public TestClass() { InstanceValue = 200; Console.WriteLine($"实例构造函数设置InstanceValue={InstanceValue}"); } } // 测试代码 Console.WriteLine(TestClass.StaticValue); // 输出静态构造函数设置StaticValue=100 → 100 var obj1 = new TestClass(); // 输出:实例构造函数设置InstanceValue=200 var obj2 = new TestClass(); // 仅输出实例构造函数信息 ``` --- ### 对比总结 | **维度** | **构造函数** | **静态构造函数** | |------------------|------------------------------------------|---------------------------------------------| | **内存影响** | 影响单个对象内存布局 | 影响类全局内存状态 | | **性能开销** | 随实例数量线性增长 | 一次性固定开销 | | **可测试性** | 可通过多实例化测试不同状态 | 需重置应用程序域才能重复测试 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值