nameof作用域扩展
在 C# 11 中,nameof
表达式的作用域得到了扩展,类型参数名称和参数名称现在可以在使用 nameof
表达式指定方法或参数声明的属性中使用。这个特性使得你可以在方法或参数声明的属性中使用 nameof
操作符来指定方法参数的名称。这个特性最常用于添加可空性分析的属性。
# 前言
在 C# 中,nameof
运算符用于获取指定变量、类型或成员的名称。这个运算符非常有用,因为它不仅可以避免硬编码字符串常量,而且可以在重构代码时更改名称而不会影响字符串常量。在 C# 11 中,nameof
运算符的作用域得到了扩展,这意味着你可以在属性声明中使用 nameof
运算符来指定方法或参数的名称。
# 示例
为了更好地理解 Extended nameof scope
特性,我们来看几个示例。
# 示例 1 - 确定方法的参数名称
假设我们有以下方法:
public void Foo(string bar)
{
// ...
}
我们现在想要在 Foo
方法中添加一个属性,该属性需要指定方法参数 bar
的名称。在 C# 11 之前,我们可以使用以下方式指定 bar
参数的名称:
[SomeAttribute("bar")]
public void Foo(string bar)
{
// ...
}
但是,在 C# 11 中,我们可以使用 nameof
运算符来指定 bar
参数的名称,如下所示:
[SomeAttribute(nameof(bar))]
public void Foo(string bar)
{
// ...
}
这样,当我们在重构 bar
参数的名称时,我们只需要更改参数的名称,而不需要同时更新属性的名称。
# 示例 2 - 确定类型参数名称
假设我们有以下泛型方法:
public void Bar<T>(T baz)
{
// ...
}
我们现在想要在 Bar
方法中添加一个属性,该属性需要指定类型参数 T
的名称。在 C# 11 之前,我们无法使用 nameof
运算符来指定类型参数的名称。但是,在 C# 11 中,我们可以使用以下方式指定类型参数 T
的名称:
[SomeAttribute(nameof(T))]
public void Bar<T>(T baz)
{
// ...
}
这样,当我们在重构 T
类型参数的名称时,我们只需要更改类型参数的名称,而不需要同时更新属性的名称。
# 示例 3 - 确定属性的参数名称
假设我们有以下属性:
public string SomeProperty { get; set; }
我们现在想要在 SomeProperty
属性上添加一个属性,该属性需要指定属性的名称。在 C# 11 之前,我们可以使用以下方式指定 SomeProperty
属性的名称:
[SomeAttribute("SomeProperty")]
public string SomeProperty { get; set; }
但是,在 C# 11 中,我们可以使用 nameof
运算符来指定属性的名称,如下所示:
[SomeAttribute(nameof(SomeProperty))]
public string SomeProperty { get; set; }
这样,当我们在重构 SomeProperty
属性的名称时,我们只需要更改属性的名称,而不需要同时更新属性的属性名称。
# 示例 4 - 添加可空性分析属性
在 C# 8 中,可空引用类型被引入。可空性分析(nullable analysis)功能使得编译器可以在编译时检测可能会导致空引用异常的代码。在 C# 11 中,Extended nameof scope
特性使得添加可空性分析属性变得更加容易。
假设我们有以下代码:
public void Baz(string? qux)
{
// ...
}
我们可以在 Baz
方法中添加一个属性,该属性指定参数 qux
不能为空,如下所示:
[NotNull(nameof(qux))]
public void Baz(string? qux)
{
// ...
}
这样,编译器会在编译时检测 qux
参数是否为空,如果为空,则会发出警告或错误。这使得代码更加健壮和可靠。
# 结论
Extended nameof scope
特性是 C# 11 中非常有用的特性之一,它使得添加属性变得更加容易,特别是在添加可空性分析属性时。我们可以使用 nameof
运算符来指定方法、参数和属性的名称,而不必担心硬编码字符串常量。这个特性可以使我们的代码更加健壮和可靠。