本文对 C# 类的系统化、深度且易理解的讲解,覆盖类的所有核心组成部分(成员、修饰符、静态 / 实例特性、构造析构、关键字等)。以 “概念定义 + 核心特性 + 代码示例 + 使用场景” 的结构,帮你构建完整的类知识体系,同时点明新手易混淆的关键点。
一、类的本质与核心定位C# 是纯面向对象语言,类(Class) 是面向对象编程(OOP)的核心载体 —— 它是对 “数据(状态)” 和 “行为(操作)” 的封装,是创建对象(实例)的 “模板”。
1
2
3
4
5
6
7
8
9
10
11
// 最基础的类结构:包含数据(字段)和行为(方法)class Phone{ // 数据:描述手机的状态(字段) string _brand; int _batteryLevel; // 行为:手机能执行的操作(方法) void Call(string number) { } void Charge() { }}
二、类的成员:完整分类与说明类的成员是类的 “组成部分”,覆盖你提到的所有类型,按功能可分为以下大类,每类都有明确的职责:
表格
成员类型
核心作用
典型示例
字段(Field)
存储类 / 对象的原始数据(底层存储)
private string _name;
方法(Method)
定义类 / 对象的行为(可执行逻辑)
public void Run() { }
属性(Property)
封装字段的访问(可控的读 / 写)
public string Name { get; set; }
构造函数
初始化类(静态构造)或对象(实例构造)
public Phone() { }
析构函数
释放对象占用的非托管资源
~Phone() { }
常量(Constant)
定义编译期固定、不可变的值
public const int MaxBattery = 100;
索引器
让对象支持 “数组式下标访问”
public string this[int index] { get; }
静态成员
属于类本身(所有实例共享)
public static int TotalPhones;
其他成员
事件、运算符重载、嵌套类等(进阶)
public event Action OnLowBattery;
关键补充:成员修饰符的规范顺序C# 编译器不强制修饰符顺序,但遵循行业规范能提升代码可读性,推荐顺序(从左到右):
访问修饰符 → 静态/实例 → 其他修饰符 → 类型/返回值 → 成员名
正确示例:
1
2
3
4
5
// 访问修饰符(public) → 静态(static) → 只读(readonly) → 类型(int) → 成员名(DefaultPort)public static readonly int DefaultPort = 8080; // 访问修饰符(private) → 实例(默认) → 类型(string) → 成员名(_ip)private string _ip;
不推荐(顺序混乱):
1
2
static public int Timeout = 30; // 静态修饰符在访问修饰符前private readonly static string Url = "https://example.com"; // 只读在静态前
三、实例成员 vs 静态成员:核心差异这是类成员最核心的分类维度,新手最易混淆,需重点理解:
1. 实例类成员(非静态)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Employee{ // 实例字段:每个员工有自己的姓名和工号 public string Name; public int Id; // 实例方法:访问实例字段和静态字段 public void ShowInfo() { Console.WriteLine(#34;姓名:{Name},工号:{Id},部门:{Department}"); } // 静态字段:所有员工共享的部门信息 public static string Department = "研发部";}// 使用实例成员Employee emp1 = new Employee();emp1.Name = "张三";emp1.Id = 1001;emp1.ShowInfo(); // 输出:姓名:张三,工号:1001,部门:研发部Employee emp2 = new Employee();emp2.Name = "李四";emp2.Id = 1002;emp2.ShowInfo(); // 输出:姓名:李四,工号:1002,部门:研发部
2. 静态字段
1
2
3
4
// 延续上面的Employee类Employee.Department = "产品部"; // 修改静态字段emp1.ShowInfo(); // 输出:姓名:张三,工号:1001,部门:产品部(emp1的部门也变了)emp2.ShowInfo(); // 输出:姓名:李四,工号:1002,部门:产品部(emp2的部门也变了)
3. 从类的外部访问静态成员
1
2
3
4
5
6
// 推荐:类名访问静态成员Console.WriteLine(Employee.Department); // 不推荐:实例名访问静态成员(编译器会警告)Employee emp = new Employee();Console.WriteLine(emp.Department); // 本质还是访问Employee.Department
4. 静态函数成员(静态方法)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static class MathTool // 静态类:只能包含静态成员,不能实例化{ // 静态字段 public static readonly double PI = 3.1415926; // 静态方法:计算圆面积(仅访问静态成员) public static double CalculateCircleArea(double radius) { return PI * radius * radius; } // 错误:静态方法不能访问实例成员(静态类中也无法定义实例成员) // public string Version = "1.0";}// 使用静态方法(无需new)double area = MathTool.CalculateCircleArea(5);Console.WriteLine(area); // 输出:78.539815
5. 其他静态类成员类型除了静态字段 / 方法,还有这些常用静态成员:
表格
静态成员类型
示例代码
核心用途
静态属性
public static string AppName { get; set; }
封装静态字段的访问
静态构造函数
static MathTool() { PI = 3.14; }
初始化静态成员(仅执行一次)
静态常量
public const int MaxValue = 100;
编译期固定值(无需加 static)
四、成员常量 vs 静态量:深度对比新手极易混淆const(常量)、static(静态字段)、static readonly(静态只读字段),以下是精准区分:
1. 成员常量(const)
1
2
3
4
5
6
7
8
9
10
11
12
class Config{ // 正确:常量声明 public const int Timeout = 30; // 错误:const不能加static // public static const string Url = "https://example.com"; // 错误:const不能后期赋值 // public const double PI; // static Config() { PI = 3.14; }}
2. 常量 vs 静态量 vs 静态只读量(核心对比)表格
特性
const(常量)
static(静态字段)
static readonly(静态只读)
赋值时机
编译期
运行期(声明 / 静态构造)
运行期(声明 / 静态构造)
可修改性
完全不可改
可改(除非 readonly)
仅静态构造中可改
支持类型
仅限基本类型
任意类型
任意类型
内存存储
嵌入 IL 代码
类静态存储区
类静态存储区
适用场景
固定不变的基础值
需动态修改的全局值
运行期初始化的全局只读值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Example{ // 常量:编译期固定 public const int MaxRetry = 3; // 静态字段:可动态修改 public static string AppVersion = "1.0.0"; // 静态只读:运行期初始化,不可修改 public static readonly DateTime AppStartDate; // 静态构造函数:初始化静态只读字段 static Example() { AppStartDate = DateTime.Now; // 运行期赋值 }}// 测试Example.AppVersion = "1.0.1"; // 静态字段可改// Example.AppStartDate = DateTime.Now; // 报错:只读字段不能赋值// Example.MaxRetry = 5; // 报错:常量不能赋值
五、属性(Property):字段的 “安全封装”属性是对字段的封装,解决了 “字段直接暴露导致数据不可控” 的问题,分为三类:
1. 自动属性(简化版)编译器自动生成私有字段(幕后字段),无需手动定义,适合简单场景。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class User{ // 自动属性:读+写 public string Username { get; set; } // 自动只读属性:仅能通过构造函数赋值 public string UserId { get; } // 自动属性:只读(私有写) public int Age { get; private set; } // 构造函数初始化只读属性 public User(string userId) { UserId = userId; Age = 18; // 私有写可在类内部赋值 }}
2. 手动属性(自定义逻辑)自定义get/set逻辑,支持数据验证、日志记录等,是属性的核心用法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Product{ // 私有字段:底层存储 private decimal _price; // 手动属性:封装_price,添加验证逻辑 public decimal Price { get { Console.WriteLine("读取价格"); return _price; } set { if (value < 0) throw new ArgumentException("价格不能为负数"); Console.WriteLine("设置价格:" + value); _price = value; } }}// 使用属性Product p = new Product();p.Price = 99.9m; // 调用set,输出:设置价格:99.9Console.WriteLine(p.Price); // 调用get,输出:读取价格 → 99.9// p.Price = -10; // 抛出异常:价格不能为负数
3. 属性的核心优势构造函数是类中用于初始化对象 / 类的特殊方法,分为实例构造函数和静态构造函数,两者差异是核心考点:
1. 实例构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Car{ public string Brand; public int Year; // 无参构造函数 public Car() { Brand = "未知"; Year = DateTime.Now.Year; Console.WriteLine("无参构造执行"); } // 有参构造函数(重载) public Car(string brand) : this() // 调用无参构造 { Brand = brand; Console.WriteLine("有参构造执行"); } // 多参数构造函数(重载) public Car(string brand, int year) : this(brand) // 调用单参数构造 { Year = year; Console.WriteLine("多参数构造执行"); }}// 测试:构造函数链式调用Car c = new Car("宝马", 2024);/* 输出顺序:无参构造执行有参构造执行多参数构造执行*/
2. 静态构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class LogManager{ // 静态字段 public static string LogPath; // 静态构造函数(仅执行一次) static LogManager() { // 初始化静态字段(模拟从配置读取) LogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log.txt"); Console.WriteLine("静态构造函数执行:初始化日志路径"); } // 静态方法 public static void WriteLog(string message) { File.AppendAllText(LogPath, #34;{DateTime.Now}: {message}\n"); }}// 第一次调用静态方法,触发静态构造函数LogManager.WriteLog("程序启动");// 第二次调用,静态构造函数不再执行LogManager.WriteLog("操作完成");
3. 对象初始化语句简化对象创建,无需定义多个构造函数,直接为属性 / 字段赋值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Book{ public string Title { get; set; } public string Author { get; set; } public int Pages { get; set; }} // 对象初始化语句(无需构造函数)Book book = new Book{ Title = "C#实战", Author = "李四", Pages = 450};
七、析构函数:对象的 “清理者”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class FileReader{ // 非托管资源:文件流 private FileStream _stream; public FileReader(string path) { _stream = new FileStream(path, FileMode.Open); } // 析构函数:释放非托管资源 ~FileReader() { // 安全释放资源(null判断) _stream.Close(); _stream.Dispose(); Console.WriteLine("析构函数执行:文件流已释放"); }}// 测试(析构函数由GC自动调用)FileReader reader = new FileReader("test.txt");reader = null; // 置为null,让GC回收GC.Collect(); // 手动触发GC(仅测试用,实际不推荐)
注意:C# 中推荐使用IDisposable接口替代析构函数,可手动控制资源释放,更灵活。
八、readonly 修饰符:运行期只读
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Order{ // 实例readonly:每个订单的ID唯一 public readonly string OrderId; // 静态readonly:所有订单的默认币种 public static readonly string DefaultCurrency; // 实例构造函数:赋值实例readonly public Order() { OrderId = Guid.NewGuid().ToString(); // 运行期生成唯一ID } // 静态构造函数:赋值静态readonly static Order() { DefaultCurrency = "CNY"; // 运行期初始化 }}Order order1 = new Order();Order order2 = new Order();Console.WriteLine(order1.OrderId); // 唯一IDConsole.WriteLine(order2.OrderId); // 另一唯一ID// order1.OrderId = "123"; // 报错:readonly字段不能赋值// Order.DefaultCurrency = "USD"; // 报错:静态readonly字段不能赋值
九、this 关键字:当前实例的 “代名词”this代表当前对象实例,主要有 4 个核心用途:
1. 区分字段与参数(同名时)
1
2
3
4
5
6
7
8
9
class Person{ private string _name; public Person(string name) { this._name = name; // this._name是字段,name是参数 }}
2. 调用同类的其他构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person{ public string Name { get; set; } public int Age { get; set; } public Person() : this("未知", 18) // 调用双参数构造 { } public Person(string name, int age) { this.Name = name; this.Age = age; }}
3. 作为参数传递给其他方法
1
2
3
4
5
6
7
8
9
10
11
12
class Person{ public void PrintInfo() { ShowDetails(this); // 将当前实例传递给方法 } private void ShowDetails(Person p) { Console.WriteLine(#34;姓名:{p.Name},年龄:{p.Age}"); }}
4. 在索引器中使用(代表当前对象)
1
2
3
4
5
6
7
8
9
10
11
class Collection{ private string[] _items = new string[10]; // 索引器:this代表当前对象 public string this[int index] { get { return _items[index]; } set { _items[index] = value; } }}
十、索引器:对象的 “数组式访问”索引器允许对象像数组一样通过[下标]访问成员,核心语法:
public 类型 this[参数列表] { get; set; }
1. 基础索引器(int 下标)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class StudentList{ private List
1
2
3
4
5
6
7
8
9
10
11
class StudentList{ // 重载索引器:string下标(根据姓名查索引) public int this[string name] { get { return _students.IndexOf(name); } }} // 使用重载索引器Console.WriteLine(list["李四"]); // 输出:1
总结(核心关键点)掌握这些核心知识点,你就能彻底理解 C# 类的设计逻辑和使用方式,后续学习继承、多态、接口等进阶内容也会更轻松。
本站是社保查询公益性网站链接,数据来自各地人力资源和社会保障局,具体内容以官网为准。
定期更新查询链接数据 苏ICP备17010502号-11