运算符名称
nameof
运算符将代码元素的名称作为 string
返回。抛出与方法参数相关的异常以及实现 INotifyPropertyChanged
时,这非常有用。
public string SayHello(string greeted)
{
if (greeted == null)
throw new ArgumentNullException(nameof(greeted));
Console.WriteLine("Hello, " + greeted);
}
在编译时评估 nameof
运算符,并将表达式更改为字符串文字。这对于以公开它们的成员命名的字符串也很有用。考虑以下:
public static class Strings
{
public const string Foo = nameof(Foo); // Rather than Foo = "Foo"
public const string Bar = nameof(Bar); // Rather than Bar = "Bar"
}
由于 nameof
表达式是编译时常量,因此可以在属性,case
标签,switch
语句等中使用它们。
使用 nameof
和 Enum
s 很方便。代替:
Console.WriteLine(Enum.One.ToString());
可以使用:
Console.WriteLine(nameof(Enum.One))
两种情况下的输出都是 One
。
nameof
运算符可以使用类似静态的语法访问非静态成员。而不是做:
string foo = "Foo";
string lengthName = nameof(foo.Length);
可以替换为:
string lengthName = nameof(string.Length);
两个例子中的输出都是 Length
。但是,后者可以防止创建不必要的实例。
虽然 nameof
运算符适用于大多数语言结构,但存在一些限制。例如,你不能在开放泛型类型或方法返回值上使用 nameof
运算符:
public static int Main()
{
Console.WriteLine(nameof(List<>)); // Compile-time error
Console.WriteLine(nameof(Main())); // Compile-time error
}
此外,如果将其应用于泛型类型,则将忽略泛型类型参数:
Console.WriteLine(nameof(List<int>)); // "List"
Console.WriteLine(nameof(List<bool>)); // "List"
有关更多示例,请参阅专用于 nameof
的此主题 。
以前版本的解决方法(更多细节)
虽然对于 6.0 之前的版本,在 C#中不存在 nameof
运算符,但是使用 MemberExpression
可以获得类似的功能,如下所示:
Version < 6
表达:
public static string NameOf<T>(Expression<Func<T>> propExp)
{
var memberExpression = propExp.Body as MemberExpression;
return memberExpression != null ? memberExpression.Member.Name : null;
}
public static string NameOf<TObj, T>(Expression<Func<TObj, T>> propExp)
{
var memberExpression = propExp.Body as MemberExpression;
return memberExpression != null ? memberExpression.Member.Name : null;
}
用法:
string variableName = NameOf(() => variable);
string propertyName = NameOf((Foo o) => o.Bar);
请注意,这种方法会导致在每次调用时创建表达式树,因此与在编译时计算并且在运行时没有开销的 nameof
运算符相比,性能要差得多。