c# - nameof用法
原連結:https://code-examples.net/zh-CN/q/1e3a41c
最重要的是nameof不會影響效能!
以前我們使用的是這樣的:
// 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 });
程式設計是個人愛好