1. 程式人生 > 其它 >c# - nameof用法

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 });
程式設計是個人愛好