扩展方法本质是编译器重写的静态调用,必须定义在非嵌套静态类中,首参数用this修饰且类型严格匹配,需using显式引入命名空间,不支持嵌套、dynamic或object泛型推导,c#14 extension块仅限单类型集中扩展。

扩展方法不是“真实例方法”,它只是编译器帮你重写的静态调用——这点不搞清,后续所有优化、调试、泛型推导都会踩坑。
扩展方法必须定义在非嵌套静态类里
这是硬性语法限制,不是风格建议。如果把 StringExtensions 嵌套在另一个类内部,或者忘了加 static 修饰符,编译器会直接报错 CS1106: Extension method must be defined in a non-nested static class。
- 静态类不能有实例构造函数,也不能被继承或实例化
- 命名空间层级不影响可用性,但客户端必须用
using显式引入该命名空间 - 常见错误:把扩展类放在
internal命名空间下却没给调用方项目加InternalsVisibleTo
第一个参数必须带 this 且类型明确
写成 this string str 可以,但 this object str 或 this IConvertible str 就会导致调用失败——因为编译器只认“完全匹配”的类型绑定。
- 泛型扩展支持,例如
this IEnumerable<t> source</t>,但调用时类型推导依赖上下文,var list = new List<int>(); list.MyMethod()</int>才能成功推导T=int - 值类型扩展要警惕装箱:对
int写扩展方法时,若参数是this object o,每次调用都会触发装箱 - 不能用
this dynamic——动态类型无法参与扩展方法绑定
C# 14 的 extension 块写法更紧凑但有约束
新语法省去了重复写 this 和类型声明,但仅适用于单一目标类型的集中扩展,不适合跨类型复用逻辑。
- 必须写在非嵌套、非泛型静态类中,且一个
extension块只能绑定一种类型(如extension(string str)) - 块内可定义方法、属性、运算符,但不能定义嵌套类型或字段
- 仍需
using引入命名空间;IntelliSense 支持良好,但部分旧版分析器可能识别不全 - 反例:试图在一个
extension块里同时扩展string和ReadOnlySpan<char></char>会编译失败
性能关键点:别在热路径里滥用字符串分配型扩展
像 str.Split().Length 这类扩展方法,每次调用都新建数组和字符串对象,高频场景下 GC 压力明显。
- 替代方案优先用
ReadOnlySpan<char></char>参数重载,例如this ReadOnlySpan<char> span</char>+span.IndexOf(...) - 避免为值类型写返回
string的扩展(如int.ToPaddedString()),改用Span<char></char>或接受char[]缓冲区的重载 - 调试时注意:IL 中看不到“扩展”痕迹,所有调用都被转成
MyExtensions.WordCount(s),所以堆栈跟踪里不会显示“实例调用”语义
最易被忽略的是作用域控制——扩展方法一旦被 using 引入,就会污染整个文件的 IntelliSense 补全列表,尤其当多个扩展类提供同名方法时,编译器不会报错,但实际调用哪个版本取决于 using 顺序和重载匹配精度。










