nameof 运算符在编译期求值生成字符串字面量,无运行时开销且支持 IDE 重命名;适用于属性、参数等符号名,不可用于表达式或嵌套空条件访问,返回纯标识符名(不含命名空间、泛型参数)。

nameof 运算符在编译期求值,生成字符串字面量,不是反射,不产生运行时开销,也不受重命名影响(支持 IDE 重命名自动更新)。
nameof 用在属性、参数、变量名上最常见
它适合替代硬编码字符串,尤其在 INotifyPropertyChanged、异常消息、日志字段名等场景。比如手动触发属性变更通知时,写 nameof(MyProperty) 比 "MyProperty" 更安全——改名后 IDE 会同步更新 nameof 表达式,而字符串不会。
- 只能作用于“可被编译器识别的符号”:变量名、字段名、属性名、方法名、类型名、命名空间名,不能用于表达式如
nameof(obj?.Prop)或nameof(list[0]) - 嵌套成员可用点号:
nameof(MyClass.MyField)、nameof(List<int>.Count)</int>都合法;但nameof(MyClass?.MyField)会报错 - 泛型类型名中,尖括号不参与输出:
nameof(List<string>)</string>结果是"List",不是"List<string>"</string>
nameof 不能代替 typeof 或反射获取完整类型信息
它只返回标识符的“名字部分”,不带命名空间、不带泛型实参、不区分大小写(因为 C# 标识符本身区分大小写,所以结果就是原样拼写)。想获取 "System.Collections.Generic.List`1[[System.String, ...]]" 这种完整名称?必须用 typeof(List<string>).FullName</string>。
-
nameof(String)→"String",不是"System.String" -
nameof(Task<int>)</int>→"Task",不是"Task<int>"</int>或"Task`1" - 对别名也返回原始标识符:
using Int = System.Int32;后,nameof(Int)仍是"Int",不是"Int32"
在异常和验证逻辑里用 nameof 避免拼写错误
参数校验是最典型的使用位置。传统写法 throw new ArgumentNullException("paramName") 容易拼错字符串,且重构时容易遗漏;换成 nameof(paramName) 就彻底规避这个问题。
void Process(string input)
{
if (input == null)
throw new ArgumentNullException(nameof(input)); // ✅ 安全、可重命名
}
- 注意:
nameof不能用于属性访问器内部引用自身,比如在set { if (value == null) throw new ArgumentNullException(nameof(value)); }是合法的,但nameof(this.MyProperty)在属性体内写,实际取的是"MyProperty",不是"this.MyProperty"的完整路径 - 在 LINQ 表达式树中不能直接用
nameof替代表达式,比如OrderBy(x => nameof(x.Name))是错的——这只会排序字符串"Name",不是按字段值排序
真正容易被忽略的是:nameof 不检查符号是否存在——它只做语法分析。如果写了 nameof(NonExistentVar),编译器会报错;但如果符号在某个作用域里被遮蔽(比如局部变量覆盖了字段),nameof 取到的就是最近作用域的那个,而不是你直觉以为的字段名。











