目录

C# 中的 nameof 关键字

nameof 表达式是 C# 6.0 引入的一个非常实用的特性。它用于在编译时获取变量、类型或成员的名称(字符串形式)。

1. 为什么要使用 nameof?

在 `nameof` 出现之前,我们通常使用硬编码的字符串来引用参数名或属性名。这样做有很大的弊端:

nameof 解决了这些问题,因为它在编译时进行求值。如果引用的名称不存在,编译器会报错。

2. 基本语法

语法非常简单:

nameof(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<T>)` “List”
别名 如果使用了 `using` 别名,`nameof` 返回别名。 `using Sys = System;` <br> `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<int>));            // 输出: 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. 总结

建议在任何需要使用代码元素名称作为字符串的地方,优先使用 nameof