====== C# 中的 nameof 关键字 ====== **nameof** 表达式是 C# 6.0 引入的一个非常实用的特性。它用于在**编译时**获取变量、类型或成员的名称(字符串形式)。 ===== 1. 为什么要使用 nameof? ===== 在 `nameof` 出现之前,我们通常使用硬编码的字符串来引用参数名或属性名。这样做有很大的弊端: * **重构困难**:如果你重命名了一个变量,硬编码的字符串不会自动更新。 * **容易出错**:拼写错误在编译时无法发现,只有在运行时才会报错。 **nameof** 解决了这些问题,因为它在编译时进行求值。如果引用的名称不存在,编译器会报错。 ===== 2. 基本语法 ===== 语法非常简单: nameof(element) * **element**: 可以是类名、方法名、属性名、参数名或变量名。 * **返回值**: 一个字符串字面量。 ===== 3. 常见使用场景 ===== ==== 3.1 参数验证 (Argument Validation) ==== 这是 `nameof` 最常见的用途。当抛出 `ArgumentNullException` 或 `ArgumentException` 时,需要提供参数的名称。 **旧写法 (不推荐):** public void ProcessUser(User user) { if (user == null) { // 如果 user 参数改名,这里容易忘记修改 throw new ArgumentNullException("user"); } } **使用 nameof (推荐):** public void ProcessUser(User user) { if (user == null) { // 编译时检查,重构安全 throw new ArgumentNullException(nameof(user)); } } ==== 3.2 INotifyPropertyChanged 实现 ==== 在 WPF、WinForms 或 MAUI 开发中,实现 `INotifyPropertyChanged` 接口时,需要传递属性名称的字符串。 public class ViewModel : INotifyPropertyChanged { private string _name; public string Name { get { return _name; } set { _name = value; // 使用 nameof(Name) 替代 "Name" PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name))); } } public event PropertyChangedEventHandler PropertyChanged; } ==== 3.3 日志记录 (Logging) ==== 在记录日志时,自动获取当前方法或类的名称,避免手动输入。 public void Execute() { try { // ... 业务逻辑 } catch (Exception ex) { // 输出: "Error in method: Execute" Logger.LogError($"Error in method: {nameof(Execute)}", ex); } } ==== 3.4 路由与控制器 (ASP.NET Core) ==== 在生成链接或重定向时,引用控制器或动作的名称。 public IActionResult Index() { // RedirectToAction("Privacy"); // 旧写法 return RedirectToAction(nameof(Privacy)); // 推荐写法 } public IActionResult Privacy() { return View(); } ===== 4. 进阶细节与注意事项 ===== ^ 特性 ^ 说明 ^ 示例 ^ 结果 ^ | **获取限定名称** | `nameof` 只返回最后一部分的名称,不包含命名空间或类前缀。 | `nameof(System.String)` | "String" | | **数组属性** | 可以获取数组的 Length 属性。 | `nameof(array.Length)` | "Length" | | **泛型** | 可以用于开放泛型类型。 | `nameof(List)` | "List" | | **别名** | 如果使用了 `using` 别名,`nameof` 返回别名。 | `using Sys = System;`
`nameof(Sys)` | "Sys" | ==== 示例代码演示 ==== using System; using System.Collections.Generic; public class Program { public static void Main() { Console.WriteLine(nameof(System.String)); // 输出: String Console.WriteLine(nameof(List)); // 输出: List Console.WriteLine(nameof(Program)); // 输出: Program Console.WriteLine(nameof(Main)); // 输出: Main var myVar = 10; Console.WriteLine(nameof(myVar)); // 输出: myVar // 即使是成员访问,也只取最后一部分 Console.WriteLine(nameof(Program.Main)); // 输出: Main } } ===== 5. 总结 ===== * **安全性**:将运行时错误转变为编译时错误。 * **可维护性**:支持 IDE 的重构工具(重命名)。 * **可读性**:代码意图更清晰。 建议在任何需要使用代码元素名称作为字符串的地方,优先使用 **nameof**。