【c# 操作符】- nameof用法


 

最重要的是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, 您不必擔心。

另請參見: nameof(C#和Visual Basic參考)


 

考慮到您在代碼中使用了變量,並且需要獲取變量的名稱並可以說將其打印出來,因此您必須使用

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM