nameof的用途是什么?

版本6.0获得了nameof一个新特性,但我不明白它的目的,因为它只是取得variables名,并在编译时将其更改为string。

我认为它可能有一些目的,当使用<T>但是当我尝试nameof(T)它只是打印我T而不是使用的types。

任何想法的目的?

如果你想重用一个属性的名字的情况下,例如,当抛出基于属性名称的exception,或处理PropertyChanged事件。 有很多情况下,你想拥有的财产的名称。

以这个例子:

 switch (e.PropertyName) { case nameof(SomeProperty): { break }; // opposed to case "SomeOtherProperty": { break;} } 

在第一种情况下,重命名SomeProperty也会改变属性的名字,否则会破坏编译。 最后一种情况没有。

这是一个非常有用的方法来保持您的代码编译和无错(sorting)。

( 来自Eric Lippert的一篇非常不错的文章,为什么infoof没有做到,而nameof做到了)

这对ArgumentException及其派生物非常有用:

 public string DoSomething(string input) { if(input == null) { throw new ArgumentNullException(nameof(input)); } ... 

现在,如果有人重构input参数的名称,exception也会保持最新。

在以前的reflection必须用来获取属性或参数的名称的地方也是有用的。

在你的例子中, nameof(T)得到了types参数的名字 – 这也可以是有用的:

 throw new ArgumentException(nameof(T), $"Type {typeof(T)} does not support this method."); 

nameof另一个用途是用于枚举 – 通常如果你想使用一个枚举的string名.ToString()

 enum MyEnum { ... FooBar = 7 ... } Console.WriteLine(MyEnum.FooBar.ToString()); > "FooBar" 

这实际上相对较慢,因为.Net拥有枚举值(即7 )并在运行时find名称。

而是使用nameof

 Console.WriteLine(nameof(MyEnum.FooBar)) > "FooBar" 

现在.Net在编译时用一个stringreplace枚举名称。


另一种用途是用于INotifyPropertyChanged和日志logging – 在这两种情况下,您都希望将调用的成员的名称传递给另一个方法:

 // Property with notify of change public int Foo { get { return this.foo; } set { this.foo = value; PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.Foo)); } } 

要么…

 // Write a log, audit or trace for the method called void DoSomething(... params ...) { Log(nameof(DoSomething), "Message...."); } 

你的问题已经expression了目的。 您必须看到这可能对logging或抛出exception很有用。

例如。

 public void DoStuff(object input) { if (input == null) { throw new ArgumentNullException(nameof(input)); } } 

这是好的, 如果我改变了variables的名字,代码将会被破坏,或者返回一个带有错误信息的exception


当然,用途不限于这种简单的情况。 只要编写variables或属性的名称是有用的,就可以使用nameof

当你考虑各种绑定和reflection的情况下,用途是多方面的。 它是一个很好的方式来把运行时错误带到编译时间。

我能想到的最常见的用例是使用INotifyPropertyChanged接口。 (基本上所有与WPF和绑定有关的东西都使用这个接口)

看看这个例子:

 public class Model : INotifyPropertyChanged { // From the INotifyPropertyChanged interface public event PropertyChangedEventHandler PropertyChanged; private string foo; public String Foo { get { return this.foo; } set { this.foo = value; // Old code: PropertyChanged(this, new PropertyChangedEventArgs("Foo")); // New Code: PropertyChanged(this, new PropertyChangedEventArgs(nameof(Foo))); } } } 

正如你所看到的,我们必须传递一个string来表示哪个属性已经改变。 用nameof我们可以直接使用属性的名字。 这可能不是什么大不了的事情。 但是,当有人更改属性Foo的名字时会发生什么情况。 使用string时,绑定将停止工作,但编译器不会警告您。 当使用nameof时,会得到一个编译器错误,即没有名称为Foo属性/参数。

请注意,一些框架使用一些reflection魔法来获取属性的名称,但是现在我们已经有了这个名字不再是必要的了

最常见的用法是在inputvalidation中,比如

 //Currently void Foo(string par) { if (par == null) throw new ArgumentNullException("par"); } //C# 6 nameof void Foo(string par) { if (par == null) throw new ArgumentNullException(nameof(par)); } 

在第一种情况下,如果重构改变par参数名称的方法,则可能会忘记在ArgumentNullException中更改该参数 。 用你的名字你不必担心这一点。

另请参阅: nameof(C#和Visual Basic参考)

正如其他人已经指出的那样,运算符的名称确实在源代码中插入了元素的名称。

我想补充一点,就重构而言这是一个非常好的主意,因为它确实使得这个string重构是安全的。 以前我使用了一个静态方法,它使用了reflection来达到同样的目的,但是这对运行时性能有影响。 运算符的名称没有运行时性能影响,它在编译时工作。 如果你看一下MSIL代码,你会发现embedded的string。 请参阅以下方法及其反汇编代码。

 static void Main(string[] args) { Console.WriteLine(nameof(args)); Console.WriteLine("regular text"); } // striped nops from the listing IL_0001 ldstr args IL_0006 call System.Void System.Console::WriteLine(System.String) IL_000C ldstr regular text IL_0011 call System.Void System.Console::WriteLine(System.String) IL_0017 ret 

但是,如果您计划混淆您的软件,则这可能是一个缺点。 embedded的string混淆之后,可能不再匹配元素的名称。 依赖这个文本的机制将会中断。 例如,包括但不限于:Reflection,NotifyPropertyChanged …

在运行时确定名称会降低某些性能,但对于混淆是安全的。 如果混淆既不要求也不计划,我会build议select使用nameof操作符。

这里有很多好的答案。 我想在C#6.0的这个特性的nameof变得方便的时候再增加一个用例。 考虑一个像Dapper这样的库,这使得DB检索更容易。 尽pipe这是一个很好的库,但是您需要在查询中硬编码属性名称,这不会让编译器find不正确的属性名称。 使用string插值和特征名称,它变得更容易和types安全。

从链接中给出的例子

没有名字

var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });

与nameof

var dog = connection.Query<Dog>($"select {nameof(Dog.Age)} = @Age, {nameof(Dog.Id)} = @Id", new { Age = (int?)null, Id = guid });

考虑到你在你的代码中使用了一个variables,并且需要得到这个variables的名字并且让它打印出来,你应该使用

 int myVar = 10; print("myVar" + " value is " + myVar.toString()); 

如果有人重构代码,并使用“myVar”的另一个名字,他/她将不得不监视你的代码中的string值,并相应地进行修改。

相反,如果你有

 print(nameof(myVar) + " value is " + myVar.toString()); 

这将有助于自动重构!

MSDN文章列出了其他几个MVC路由(真正为我点击这个概念的例子)。 (格式)的说明段落如下:

  • 在代码中报告错误时,
  • 连接模型 – 视图 – 控制器(MVC)链接,
  • 射击财产变更事件等,

你经常想要捕获一个方法的string名称 。 使用nameof有助于在重命名定义时保持您的代码有效。

在必须使用string文字来引用定义之前,在重命名代码元素时这很脆弱因为工具不知道要检查这些string文字。

已被接受/最高评分的答案已经给出了几个很好的具体例子

ASP.NET Core MVC项目通过使用RedirectToAction方法在AccountController.csManageController.cs使用nameof来引用控制器中的操作。

例:

 return RedirectToAction(nameof(HomeController.Index), "Home"); 

这转化为:

 return RedirectToAction("Index", "Home"); 

并采取用户到“主页”控制器的“索引”行动,即/Home/Index

nameof运算符的目的是提供工件的源名称。

通常,源名称与元数据名称相同:

 public void M(string p) { if (p == null) { throw new ArgumentNullException(nameof(p)); } ... } public int P { get { return p; } set { p = value; NotifyPropertyChanged(nameof(P)); } } 

但是,情况并非总是如此:

 using i = System.Int32; ... Console.WriteLine(nameof(i)); // prints "i" 

要么:

 public static string Extension<T>(this T t) { return nameof(T); returns "T" } 

我一直给它的一个用途是命名资源:

 [Display( ResourceType = typeof(Resources), Name = nameof(Resources.Title_Name), ShortName = nameof(Resources.Title_ShortName), Description = nameof(Resources.Title_Description), Prompt = nameof(Resources.Title_Prompt))] 

事实是,在这种情况下,我甚至不需要生成的属性来访问资源,但现在我有编译时检查资源是否存在。

nameof关键字的用法之一nameof 编程方式在wpf中设置Binding

要设置Binding你必须设置Pathstring,并与nameof关键字,可以使用重构选项。

例如,如果在UserControlIsEnable依赖项属性,并且想要将其绑定到UserControl中某个CheckBox IsEnable ,则可以使用以下两个代码:

 CheckBox chk = new CheckBox(); Binding bnd = new Binding ("IsEnable") { Source = this }; chk.SetBinding(IsEnabledProperty, bnd); 

 CheckBox chk = new CheckBox(); Binding bnd = new Binding (nameof (IsEnable)) { Source = this }; chk.SetBinding(IsEnabledProperty, bnd); 

很明显,第一个代码不能重构,但后一个…

以前我们正在使用类似的东西:

 // Some form. SetFieldReadOnly( () => Entity.UserName ); ... // Base form. private void SetFieldReadOnly(Expression<Func<object>> property) { var propName = GetPropNameFromExpr(property); SetFieldsReadOnly(propName); } private void SetFieldReadOnly(string propertyName) { ... } 

原因 – 编译时间安全。 没有人可以默默地重命名属性和破坏代码逻辑。 现在我们可以使用nameof()。