最重要的是nameof不會影響性能!
nameof有什么用?主要用解決 類成員名做參數替代成員們的字符串做參數,如下:
using System; namespace csharp6 { internal class Program { private static void Main(string[] args) { if (args==null) { throw new ArgumentNullException("args");//舊的寫法 變量名的字符串做參數 //throw new ArgumentNullException(nameOf(args));//新的寫法 避免了args變量名更改后,忘記更改字符串"args",因為字符串編譯器是不錯提示錯誤的 } } } }
這樣非常有利於后期項目維護,比如我們在使用MVC開發時候,后端返回到某個視圖,我們平時喜歡寫字符串的形式,如果項目越來越大,后期突然哪個控制器或者動作不用了,使用字符串的形式維護起來就非常麻煩,用nameof就可以很好的解決,最重要的是不會影響性能!
nameof 運算符
nameof是C#6新增的一個關鍵字運算符,主要作用是方便獲取類型、成員和變量的簡單字符串名稱(非完全限定名),意義在於避免我們在代碼中寫下固定的一些字符串,這些固定的字符串在后續維護代碼時是一個很繁瑣的事情。比如上面的代碼改寫后:
using System; namespace csharp6 { internal class Program { private static void Main(string[] args) { if (args==null) { throw new ArgumentNullException(nameof(args)); } } } }
我們把固定的 "args" 替換成等價的 nameof(args) 。按照慣例,貼出來兩種方式的代碼的IL。
"args"方式的IL代碼
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 22 (0x16) .maxstack 2 .locals init ([0] bool V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldnull IL_0003: ceq IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: brfalse.s IL_0015 IL_0009: nop IL_000a: ldstr "args" IL_000f: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) IL_0014: throw IL_0015: ret } // end of method Program::Main
nameof(args)方式的IL代碼:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 22 (0x16) .maxstack 2 .locals init ([0] bool V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldnull IL_0003: ceq IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: brfalse.s IL_0015 IL_0009: nop IL_000a: ldstr "args" IL_000f: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) IL_0014: throw IL_0015: ret } // end of method Program::Main
一樣一樣的,我是沒看出來有任何的差異,,,so,這個運算符也是一個編譯器層面提供的語法糖,編譯后就沒有nameof的影子了。
3. nameof 注意事項
nameof可以用於獲取具名表達式的當前名字的簡單字符串表示(非完全限定名)。注意當前名字這個限定,比如下面這個例子,你覺得會輸出什么結果?
using static System.Console; using CC = System.ConsoleColor; namespace csharp6 { internal class Program { private static void Main() { WriteLine(nameof(CC));//CC WriteLine(nameof(System.ConsoleColor));//ConsoleColor } } }
第一個語句輸出"CC",因為它是當前的名字,雖然是指向System.ConsoleColor枚舉的別名,但是由於CC是當前的名字,那么nameof運算符的結果就是"CC"。
第二個語句輸出了"ConsoleColor",因為它是System.ConsoleColor的簡單字符串表示,而非取得它的完全限定名,如果想取得"System.ConsoleColor",那么請使用 typeof(System.ConsoleColor).FullName 。再比如微軟給的例子: nameof(person.Address.ZipCode) ,結果是"ZipCode"。
以上內容來自:
https://www.cnblogs.com/lsgsanxiao/p/10977335.html
以前我們使用的是這樣的:
// 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()了。
如果要重用屬性名稱,例如在基於屬性名稱引發異常或處理 PropertyChanged
事件時,該怎么辦? 在很多情況下,您都希望使用屬性名稱。
舉個例子:
switch (e.PropertyName) { case nameof(SomeProperty): { break; } // opposed to case "SomeOtherProperty": { break; } }
在第一種情況下,重命名 SomeProperty
也將更改屬性的名稱,否則將中斷編譯。 最后一種情況沒有。
這是保持代碼編譯和消除錯誤(排序)的一種非常有用的方法。
( Eric Lippert的一篇非常不錯的文章, 為什么 infoof
沒能做到,而 nameof
卻做到了)
對於 ArgumentException
及其派生類確實非常有用:
public string DoSomething(string input) { if(input == null) { throw new ArgumentNullException(nameof(input)); } ...
現在,如果有人重構 input
參數的名稱,該異常也將保持最新狀態。
在某些以前必須使用反射來獲取屬性或參數名稱的地方,它也很有用。
在您的示例中, nameof(T)
獲取類型參數的名稱-這也可能有用:
throw new ArgumentException(nameof(T), $"Type {typeof(T)} does not support this method.");
nameof
另一種用法是用於枚舉-通常,如果您想要使用 .ToString()
的枚舉的字符串名稱:
enum MyEnum { ... FooBar = 7 ... } Console.WriteLine(MyEnum.FooBar.ToString()); > "FooBar"
由於.Net保留枚舉值(即 7
)並在運行時查找名稱,因此這實際上相對較慢。
而是使用 nameof
:
Console.WriteLine(nameof(MyEnum.FooBar)) > "FooBar"
現在,.Net在編譯時用字符串替換枚舉名稱。
還有另一個用途是用於 INotifyPropertyChanged
和日志記錄-在兩種情況下,您都希望將要調用的成員的名稱傳遞給另一個方法:
// 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...."); }
我能想到的最常見的用例是使用 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))); } } }
如您所見,我們必須傳遞一個字符串以指示哪個屬性已更改。 使用 nameof
我們可以直接使用屬性的名稱。 這似乎沒什么大不了的。 但是想像一下當有人更改屬性 Foo
的名稱時會發生什么。 使用字符串時,綁定將停止工作,但編譯器不會警告您。 使用nameof時,會出現一個編譯器錯誤,即沒有名稱為 Foo
屬性/參數。
請注意,某些框架使用一些反射魔術來獲取屬性的名稱,但是現在我們有了nameof,它不再是必需的 。
最常見的用法是在輸入驗證中,例如
//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, 您不必擔心。
考慮到您在代碼中使用了變量,並且需要獲取變量的名稱並可以說將其打印出來,因此您必須使用
int myVar = 10; print("myVar" + " value is " + myVar.toString());
然后如果有人重構代碼並為“ myVar”使用另一個名稱,則他/她將必須注意代碼中的字符串值並相應地對其進行處理。
相反,如果您有
print(nameof(myVar) + " value is " + myVar.toString());
這將有助於自動重構!
nameof
關鍵字的用法之一是用於以 編程方式 在wpf中設置 Binding
。
要設置 Binding
您必須使用字符串和 nameof
關鍵字設置 Path
,可以使用Refactor選項。
例如,如果您在 UserControl
具有 IsEnable
依賴項屬性,並且要將其綁定到 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);
很明顯,第一個代碼無法重構,而第二個代碼可以重構。
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))]
事實是,在這種情況下,我什至不需要生成的屬性來訪問資源,但是現在有了編譯時檢查資源是否存在。
C#6.0的 nameof
功能變得很方便的另一個用例 -考慮像 Dapper 這樣的庫,它使DB檢索更加容易。 盡管這是一個很棒的庫,但是您需要在查詢中對屬性/字段名稱進行硬編碼。 這意味着如果您決定重命名屬性/字段,則很可能會忘記更新查詢以使用新的字段名。 使用字符串插值和 nameof
功能,代碼變得更加易於維護和類型安全。
從鏈接中給出的示例
沒有名字
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 });
以上內容來自: https://code-examples.net/zh-CN/q/1e3a41c