静态成员与扩展方法
static 字段与方法
static 成员属于类型本身,而非某个实例。所有实例共享同一份 static 字段,static 方法通过 类名.成员 调用,无需创建对象。
示例
CSHARP
class Counter
{
public static int TotalCount = 0;
public int InstanceId;
public Counter(int id)
{
InstanceId = id;
TotalCount++;
}
public static void Report()
{
Console.WriteLine($"已创建 {TotalCount} 个实例");
}
}
Counter a = new Counter(1);
Counter b = new Counter(2);
Counter.Report();
Console.WriteLine(Counter.TotalCount);
TEXT
已创建 2 个实例
2
💡
static 方法中不能使用 this,也不能直接访问实例成员,只能访问其他 static 成员。
静态构造函数
静态构造函数在类首次被访问时自动执行一次,且仅一次。它不能有访问修饰符和参数,常用于初始化 static 字段。
示例
CSHARP
class Config
{
public static readonly DateTime StartTime;
static Config()
{
StartTime = DateTime.Now;
Console.WriteLine("静态构造函数已执行");
}
}
Console.WriteLine("准备访问 Config");
Console.WriteLine(Config.StartTime);
Console.WriteLine(Config.StartTime);
TEXT
准备访问 Config
静态构造函数已执行
2026/06/28 10:00:00
2026/06/28 10:00:00
⚠️ 静态构造函数只触发一次,即使多次访问该类的 static 成员也不会重复执行。
static 类(工具类模式)
用 static class 声明的类不能被实例化,也不能被继承,所有成员必须都是 static 的,适合封装工具方法。
示例
CSHARP
static class MathHelper
{
public static double Square(double x) => x * x;
public static double Hypotenuse(double a, double b) => Math.Sqrt(Square(a) + Square(b));
}
Console.WriteLine(MathHelper.Square(3));
Console.WriteLine(MathHelper.Hypotenuse(3, 4));
TEXT
9
5
📌 尝试
new MathHelper() 会导致编译错误,static 类无法创建实例。
const 与 static readonly
| 特性 | const |
static readonly |
|---|---|---|
| 赋值时机 | 编译时 | 运行时 |
| 值类型 | 仅内建类型 | 任意类型 |
| 是否可变 | 不可变 | 构造函数中赋值后不可变 |
示例
CSHARP
class Settings
{
public const int MaxRetry = 3;
public static readonly DateTime LaunchTime;
static Settings()
{
LaunchTime = DateTime.Now;
}
}
Console.WriteLine(Settings.MaxRetry);
Console.WriteLine(Settings.LaunchTime);
TEXT
3
2026/06/28 10:00:00
⚠️
const 值在编译时嵌入调用方程序集,修改 const 后所有引用方需重新编译。static readonly 在运行时读取,更安全。
扩展方法
扩展方法在不修改原始类型的前提下,为其"添加"方法。定义在 static 类中,第一个参数前加 this 关键字,即可像实例方法一样调用。
示例
CSHARP
static class StringExt
{
public static bool IsEmpty(this string s) => s.Length == 0;
public static string Repeat(this string s, int count)
{
var sb = new StringBuilder();
for (int i = 0; i < count; i++) sb.Append(s);
return sb.ToString();
}
}
Console.WriteLine("hello".IsEmpty());
Console.WriteLine("ab".Repeat(3));
TEXT
False
ababab
💡 扩展方法本质是静态方法调用,编译器将
s.IsEmpty() 转译为 StringExt.IsEmpty(s)。实例方法优先级高于扩展方法。
扩展方法的应用(LINQ 基础)
LINQ 的链式语法正是基于扩展方法实现的。System.Linq.Enumerable 中的 Where、Select、OrderBy 等都是 IEnumerable<T> 的扩展方法。
示例
CSHARP
static class EnumerableExt
{
public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
foreach (var item in source)
{
if (predicate(item)) yield return item;
}
}
}
int[] nums = { 1, 2, 3, 4, 5, 6 };
var even = nums.MyWhere(n => n % 2 == 0);
Console.WriteLine(string.Join(", ", even));
TEXT
2, 4, 6
🚀 理解扩展方法原理后,阅读 LINQ 源码将不再困难——它们就是精心设计的扩展方法集合。
partial 类
partial 关键字允许将一个类的定义拆分到多个文件中,编译时合并为一个完整类。常用于自动生成代码与手写代码分离。
示例
CSHARP
partial class User
{
public string Name { get; set; }
public User(string name) => Name = name;
}
partial class User
{
public void Greet() => Console.WriteLine($"你好,{Name}");
}
var u = new User("小明");
u.Greet();
TEXT
你好,小明
📌 WinForms、WPF、EF Core 等框架大量使用 partial 类,将设计器生成代码与业务逻辑分开。
partial 方法
partial 方法在 partial 类的一部分中声明,另一部分中可选实现。若未实现,编译器会移除调用处的代码,零开销。C# 9 开始支持无签名限制的 partial 方法。
示例
CSHARP
partial class Order
{
public int Amount { get; set; }
partial void OnCreated();
public Order(int amount)
{
Amount = amount;
OnCreated();
}
}
partial class Order
{
partial void OnCreated() => Console.WriteLine("订单已创建");
}
var o = new Order(100);
Console.WriteLine(o.Amount);
TEXT
订单已创建
100
💡 若删除第二个 partial 类中的
OnCreated 实现,程序仍可编译通过,且调用处会被编译器自动移除。
❓ 常见问题
Q static 方法能访问实例字段吗?
A 不能。static 方法不与任何实例关联,必须通过对象引用才能访问实例成员。
Q const 和 static readonly 该选哪个?
A 如果是编译期可确定的简单常量用 const;如果是运行时才能确定的值或引用类型,用 static readonly。
Q 扩展方法能访问私有成员吗?
A 不能。扩展方法本质是静态方法,只能访问公共成员。
Q partial 类的所有部分必须在同一程序集吗?
A 是的,partial 类的所有部分必须在同一程序集和同一命名空间中。
📖 小节
static字段在所有实例间共享,static方法通过类名调用- 静态构造函数在类首次访问时执行一次,用于初始化 static 成员
static class不可实例化和继承,适合工具类const是编译时常量,static readonly是运行时常量- 扩展方法用
this参数为现有类型添加方法,是 LINQ 的基础 partial类将定义拆分到多个文件,编译时合并partial方法提供可选钩子,未实现时调用被编译器移除
📝 作业
- 编写一个
static class ArrayHelper,提供Max(int[] arr)和Average(int[] arr)两个静态方法,并在 Main 中测试 - 为
IEnumerable<int>编写一个扩展方法MySum,计算整数序列的总和,不使用 LINQ - 创建一个
partial class Logger,在一个部分中定义partial void OnLog(string message)声明和Log(string msg)方法(内部调用 OnLog),在另一个部分中实现 OnLog 输出到控制台 - 定义一个
const字段和一个static readonly字段,编写代码验证 const 在编译时替换而 static readonly 在运行时取值(提示:分别在另一个程序集中引用并观察修改后的行为)



