class Person {
public string Name;
// 构造函数
public Person(string name) {
this.Name = name; // 初始化成员
}
}
核心特性
强制命名规则:必须与类名完全相同。
无返回值:不能使用 void 或其他返回类型。
自动调用:仅通过 new 触发,不可显式调用。
隐式默认构造:未定义时编译器自动生成无参构造;若自定义任意构造,则默认构造失效。
(2)类型与使用场景
实例构造函数
作用:初始化实例成员变量。
重载支持:参数列表不同的多个构造方法。
csharp复制代码
class Car {
public string Model;
public int Year;
// 无参构造
public Car() { Model = "Unknown"; }
// 带参构造
public Car(string model, int year) {
Model = model;
Year = year;
}
}
静态构造函数
作用:初始化静态成员,在类首次加载时执行(首次实例化或访问静态成员前)。
特性:
用 static 修饰,无访问修饰符(隐式私有)。
每个类仅允许一个,且无参数。
csharp复制代码
class Logger {
public static string LogPath;
static Logger() {
LogPath = @"C:\logs\app.log"; // 初始化静态变量
}
}
私有构造函数
作用:禁止类实例化,适用于工具类或单例模式。
示例:
csharp复制代码
public class Utility {
private Utility() { } // 外部无法 new
public static void Print() { ... }
}
(3)调用链与继承
调用同级构造:this(),复用当前类的其他构造逻辑
csharp复制代码
class Rectangle {
public int Width, Height;
public Rectangle() : this(10, 5) { } // 调用带参构造
public Rectangle(int w, int h) {
Width = w; Height = h;
}
}
调用基类构造:base(),子类必须通过 base 显式调用父类构造(若父类无默认构造):
csharp复制代码
class Vehicle {
public int Speed;
public Vehicle(int speed) { Speed = speed; }
}
class Car : Vehicle {
public Car(int speed) : base(speed) { } // 必须传递参数
}
(4)关键注意事项
子类构造规则
未显式调用 base 时,编译器自动尝试调用父类无参构造;若无则报错。
执行顺序:父类构造 → 子类构造。
避免常见错误
自定义带参构造后,需显式添加无参构造(否则子类可能报错)。
静态构造中避免耗时操作(影响首次加载性能)。
性能优化
减少构造函数的重复初始化逻辑,用 this() 复用代码。
值类型(如 struct)的默认构造由编译器自动生成,无需定义。
(5)应用场景示例
csharp复制代码
// 单例模式(私有构造 + 静态实例)
public class AppConfig {
private static AppConfig _instance;
public static AppConfig Instance => _instance ??= new AppConfig();
private AppConfig() { } // 禁止外部实例化
}
// 带继承链的构造调用
class Animal {
public string Type;
public Animal(string type) => Type = type;
}
class Dog : Animal {
public string Breed;
public Dog(string breed) : base("Mammal") {
Breed = breed;
}
}
(6)最佳实践
工具类设计 → 私有构造
全局配置初始化 → 静态构造
对象复用 → 构造链 this()
跨层初始化 → 显式 base()
3、析构函数
(1)本质与作用
析构函数是类的特殊成员函数,用于对象销毁前执行资源清理(如关闭文件、释放非托管资源)。
语法:~类名(),无参数与返回类型(如 ~MyClass() { ... })。
(2)与构造函数的对比
特性
构造函数
析构函数
执行时机
对象创建时自动调用
对象销毁时自动调用
命名
与类名相同
类名前加 ~
数量限制
可重载(多个)
仅允许一个
调用控制
可通过 new 触发
完全由垃圾回收器(GC)控制
(3)关键限制与特性
使用约束
仅适用于类(不适用于结构体)。
不可继承或重载,且不能被显式调用。
禁止添加访问修饰符(如 public)或参数。
执行机制
由垃圾回收器(GC)在对象不可达时自动触发,具体时机不可预测。
程序退出时,所有未析构的对象会按继承链反向顺序调用析构函数(子类→父类)。
示例:继承链析构顺序
csharp复制代码
class A { ~A() => Console.WriteLine("A destroyed"); }
class B : A { ~B() => Console.WriteLine("B destroyed"); }
// 输出:B destroyed → A destroyed
private int _age; // 私有整型字段
public string Name; // 公有字符串字段
核心特性
存储位置:值类型字段存储于栈内存,引用类型字段存储堆内存地址。
生命周期:与所属对象实例绑定(实例字段)或与类型共存(静态字段)。
默认值:未显式初始化时,数值类型为 0,引用类型为 null。
(2)字段的分类与作用
分类
修饰符
作用
示例
实例字段
无
存储对象状态数据
private int _id;
静态字段
static
全局共享数据,类级别存储
public static int Count;
只读字段
readonly
仅允许在声明或构造函数中赋值
private readonly string _key;
常量字段
const
编译时确定值,不可修改
public const float PI = 3.14f;
readonly 与 const:
const 必须在声明时赋值,且仅支持基本类型。
readonly 可在构造函数赋值,支持任意类型。
csharp复制代码
public class Config {
public const string Env = "Prod"; // 正确
public readonly string DbPath;
public Config() { DbPath = "C:/Data"; } // 构造函数赋值
}
(3)关键注意事项
初始化要求
常量字段 (const) 必须声明时初始化。
只读字段 (readonly) 必须在声明或构造函数中初始化 。
访问安全
避免将字段设为 public,防止外部直接篡改内部状态。
静态字段需注意线程安全(如用 lock 同步)。
性能优化
频繁访问的字段可标记为 readonly 减少意外修改风险 。
大型对象避免过多实例字段,防止内存碎片。
(4)典型应用场景
csharp复制代码
// 场景1:存储对象状态
public class Person {
private int _age; // 私有字段
public string Name { get; } // 只读属性(通过构造函数赋值)
public Person(string name) => Name = name;
}
// 场景2:全局配置(静态只读字段)
public static class AppConfig {
public static readonly string ConnectionString = "Server=...";
}
// 场景3:枚举替代方案(常量字段分组)
public class ErrorCodes {
public const int NotFound = 404;
public const int Forbidden = 403;
}
(5)开发建议
优先使用属性封装字段,增强代码健壮性。
对敏感数据(如密钥)使用 readonly + 私有字段组合。
5、属性
(1)基本概念与作用
属性(Property) 是类中封装字段的成员,提供对私有字段的安全访问机制。核心作用:
封装性:隐藏字段实现细节,仅暴露安全访问接口。
数据验证:在 set 访问器中添加逻辑(如非空检查、范围验证)。
计算属性:动态生成值(如全名 = 名 + 姓)。
示例:基础属性定义
csharp复制代码
public class Person
{
private string _name; // 私有字段
public string Name // 属性
{
get { return _name; }
set {
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("姓名不能为空");
_name = value;
}
}
}
(2)分类与语法
读写属性
同时包含 get(读取)和 set(写入)访问器。
自动属性:编译器自动生成私有字段(简化代码):
csharp复制代码
public string Name { get; set; } = "Unknown"; // 默认值初始化
只读属性:仅含 get 访问器,初始化后不可修改:
csharp复制代码
public int Age { get; } = 18; // 构造函数或初始化器赋值
访问器权限控制:为 get/set 单独设置访问级别:
csharp复制代码
public string Id { get; private set; } // 外部只读,类内可写
高级特性:
init 访问器(C# 9+):仅对象初始化时可赋值:
csharp复制代码
public required string Email { get; init; } // 必需属性
复制代码
- 表达式体属性:单行逻辑简化:
csharp复制代码
public string FullName => $"{FirstName} {LastName}";
(3)关键注意事项
性能优化:
避免在属性访问器中执行耗时操作(如数据库查询)。
优先使用自动属性,除非需额外逻辑。
数据绑定支持:
实现 INotifyPropertyChanged 接口,通知界面更新:
csharp复制代码
public event PropertyChangedEventHandler? PropertyChanged;
public string Name
{
set {
_name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
(4)与字段的区别
特性
字段(Field)
属性(Property)
数据验证
不支持
支持(通过 set 访问器)
计算逻辑
不支持
支持(动态返回值)
访问控制
仅通过访问修饰符
可单独控制 get/set 权限
接口实现
不可用于接口
可用于接口定义
封装原则:字段通常设为 private,通过属性对外提供受控访问:
csharp复制代码
private string _name; // 私有字段
public string Name { // 封装属性
get => _name;
set {
if (!string.IsNullOrEmpty(value))
_name = value;
}
}
(5)实际应用场景
数据验证
csharp复制代码
private int _age;
public int Age
{
get => _age;
set => _age = value >= 0 ? value : throw new ArgumentException("年龄不能为负");
}
延迟加载
csharp复制代码
private List<string>? _data;
public List<string> Data
{
get => _data ??= LoadData(); // 首次访问时加载
}
兼容旧代码
csharp复制代码
// 旧字段升级为属性(保持API兼容)
public string LegacyField { get; set; } // 替换原 public 字段
(6)最佳实践总结
优先使用属性而非公共字段:确保封装性和扩展性。
为必需属性添加 required 修饰符:强制调用方初始化(C# 11+)。
避免过度复杂逻辑:保持属性简洁,复杂操作移至方法中。
单元测试验证:确保 set 验证逻辑和 get 计算正确性。
6、索引器
(1)核心概念
本质与作用
索引器是特殊属性,允许类或结构体的实例像数组一样通过索引访问元素。
核心价值:简化集合类操作,提供直观的数据访问语法(如 obj[index])。
基本语法结构
csharp复制代码
public 返回值类型 this[参数类型 参数名]
{
get { /* 返回索引对应的值 */ }
set { /* 设置索引对应的值(value关键字) */ }
}
(2)实现步骤与示例
基础实现(封装数组)
索引器使用 this 关键字定义。
get/set 访问器控制读写逻辑(可只实现其一)。
csharp复制代码
public class IntCollection
{
private int[] _data = new int[10];
public int this[int index]
{
get => _data[index];
set => _data[index] = value;
}
}
// 使用示例
var collection = new IntCollection();
collection[0] = 100; // 调用set
Console.WriteLine(collection[0]); // 输出100(调用get)
多维索引器(如矩阵):支持多参数(如 row, col)实现多维访问
csharp复制代码
public class Matrix
{
private int[,] _grid = new int[3, 3];
public int this[int row, int col]
{
get => _grid[row, col];
set => _grid[row, col] = value;
}
}
// 使用示例
var matrix = new Matrix();
matrix[1, 2] = 5; // 设置第2行第3列的值
非整数索引(如字典式访问):索引参数可为任意类型(字符串、枚举等)
csharp复制代码
public class ConfigLoader
{
private Dictionary<string, string> _configs = new();
public string this[string key]
{
get => _configs[key];
set => _configs[key] = value;
}
}
// 使用示例
var config = new ConfigLoader();
config["Timeout"] = "30"; // 字符串作为索引
(3)关键特性与限制
重载支持 :同一类中可定义多个索引器(参数类型或数量不同)
csharp复制代码
public string this[int id] { ... }
public string this[string name] { ... } // 重载
使用限制
必须是实例成员(不能声明为 static)。
无法定义可选参数或使用 params 关键字。
访问性需与类一致(如公共类的索引器必须为 public)。
异常处理 :需手动检查索引有效性(如防止数组越界):
csharp复制代码
get
{
if (index < 0 || index >= _data.Length)
throw new IndexOutOfRangeException();
return _data[index];
}
class Calculator {
// 参数数量不同
public int Add(int a, int b) => a + b;
public int Add(int a, int b, int c) => a + b + c;
// 参数类型不同
public double Add(double a, double b) => a + b;
}
(3)构造函数重载
作用:提供多种对象初始化方式。
规则:与方法重载一致,通过 this 关键字复用代码。
csharp复制代码
class Person {
public string Name;
public int Age;
// 无参构造
public Person() : this("Unknown", 0) {}
// 全参构造
public Person(string name, int age) {
Name = name;
Age = age;
}
}
(4)运算符重载
规则:
使用 operator 关键字定义静态方法(如 +, ==)。
至少一个参数为当前类类型。
示例(重载 + 运算符):
csharp复制代码
class Vector {
public int X, Y;
public Vector(int x, int y) { X = x; Y = y; }
public static Vector operator +(Vector v1, Vector v2) {
return new Vector(v1.X + v2.X, v1.Y + v2.Y);
}
}
// 使用:Vector v3 = v1 + v2;