web-dev-qa-db-ja.com

Nameofの目的は何ですか?

バージョン6.0にはnameofの新機能が追加されましたが、コンパイル時に変数名を受け取り、それを文字列に変更するだけなので、その目的はわかりません。

私は<T>を使用するときには何らかの目的があると思いましたが、nameof(T)を使おうとすると、使用されている型の代わりにTが表示されるだけです。

目的上の任意のアイデア?

218
atikot

たとえば、プロパティ名に基づいて例外をスローする場合やPropertyChangedname__イベントを処理する場合など、プロパティの名前を再利用したい場合はどうでしょうか。あなたが財産の名前を知りたいと思うであろう多くの場合があります。

この例を見てください。

switch (e.PropertyName)
{
    case nameof(SomeProperty):
    { break; }

    // opposed to
    case "SomeOtherProperty":
    { break; }
}

最初のケースでは、SomePropertyname__の名前を変更すると、プロパティの名前も変更されるか、コンパイルが中断されます。最後のケースは違います。

これは、コードをコンパイルしてバグがないようにする(ソート)ために非常に便利な方法です。

Eric Lippertによる非常に良い記事 なぜinfoofname__が成功しなかったのに対し、nameofname__は成功しなかったのか)

269
Patrick Hofman

それはArgumentExceptionとその派生物にとって本当に便利です:

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

誰かがinputパラメータの名前をリファクタリングすると、例外も最新の状態に保たれます。

これは、以前はプロパティやパラメータの名前を取得するためにリフレクションを使用しなければならなかった場所でも便利です。

あなたの例ではnameof(T)はtypeパラメータの名前を取得します - これは同じく役に立つかもしれません:

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

nameofのもう1つの用途は列挙型です。通常、列挙型の文字列名が必要な場合は.ToString()を使用します。

enum MyEnum { ... FooBar = 7 ... }

Console.WriteLine(MyEnum.FooBar.ToString());

> "FooBar"

.Netがenum値(つまり7)を保持し、実行時に名前を見つけるので、これは実際には比較的遅いです。

代わりにnameofを使用してください。

Console.WriteLine(nameof(MyEnum.FooBar))

> "FooBar"

今すぐ.NETはコンパイル時に列挙型の名前を文字列に置き換えます。


さらに別の用途は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....");
}
157
Keith

C#6.0のnameof機能が便利になるもう一つのユースケース - Dapper のようなライブラリを考えてください。これは素晴らしいライブラリですが、クエリ内でプロパティ/フィールド名をハードコードする必要があります。これが意味することは、あなたがあなたのプロパティ/フィールドの名前を変更することにした場合、あなたが新しいフィールド名を使うためにクエリを更新することを忘れる可能性が高いということです。文字列補間とnameof機能により、コードの保守と型保証がはるかに簡単になります。

リンクの例から

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 });
24
sateesh

あなたの質問はすでに目的を表しています。これはログに記録したり、例外をスローするのに役立つかもしれないことに気づかなければなりません。

例えば。

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

これは良いことです、 変数の名前を変更すると、コードが代わりに壊れるか、間違ったメッセージと共に例外を返します


もちろん、用途はこの単純な状況に限定されません。変数やプロパティの名前をコーディングすると便利な場合はいつでもnameofを使用できます。

あなたが様々な束縛と反射の状況を考えるとき、用途は多様です。実行時のエラーをコンパイル時に反映させるための優れた方法です。

21
Jodrell

私が考えることができる最も一般的なユースケースは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という名前のプロパティ/引数がないというコンパイラエラーが発生します。

いくつかのフレームワークではプロパティの名前を取得するためにリフレクションマジックを使用していますが、現在ではこれはもう必要ではありません

12
Roy T.

最も一般的な使用法は、次のような入力検証です。

//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リファレンス) も参照してください。

8
Massimo Prota

他の人がすでに指摘したように、nameof演算子は要素が与えられた名前をソースコードに挿入します。

この文字列のリファクタリングを安全にするので、これはリファクタリングの観点からは本当に良い考えであることを付け加えたいと思います。以前は、同じ目的でリフレクションを利用した静的メソッドを使用しましたが、実行時のパフォーマンスに影響があります。 nameof演算子は実行時のパフォーマンスに影響を与えません。コンパイル時に機能します。 MSILコードを見ると、文字列が埋め込まれているのがわかります。次のメソッドとその逆アセンブリコードを参照してください。

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

ただし、ソフトウェアを難読化することを計画している場合は、これが欠点になることがあります。難読化後、埋め込まれた文字列は要素の名前と一致しなくなります。このテキストに頼るメカニズムは壊れます。その例としては、Reflection、NotifyPropertyChangedなどがありますが、これらに限定されません。

実行時に名前を決定するとパフォーマンスはいくらか低下しますが、難読化には安全です。難読化が必須でも計画もされていない場合は、nameof演算子を使用することをお勧めします。

6
cel sharp

ASP.NET Core MVCプロジェクトでは、 AccountController.cs および ManageController.csnameofRedirectToActionメソッドと共に使用して、コントローラー内のアクションを参照します。

例:

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

これは次のように解釈されます。

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

そして、ユーザを 'Home'コントローラの 'Index'アクション、すなわち/Home/Indexに連れて行きます。

6
Fred

あなたがあなたのコードで変数を使用し、変数の名前を取得する必要があると考えてみましょう、そしてそれをprint printと言わせてください。

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

そして、もし誰かがそのコードをリファクタリングして "myVar"のために別の名前を使うと、彼/彼女はあなたのコードの文字列値を監視しそれに応じてそれを変更しなければならないでしょう。

代わりに

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

自動的にリファクタリングするのに役立ちます。

5
cnom

MSDNの記事は、MVCルーティング(この概念を実際にクリックした例)をリストしています。 (フォーマットされた)説明の段落は次のとおりです。

  • コードのエラーを報告する場合、
  • model-view-controller(MVC)リンクの接続、
  • プロパティ変更イベントなどの発火、

多くの場合、メソッドの文字列名をキャプチャします。 nameofを使用すると、定義の名前を変更するときにコードを有効に保つことができます

定義を参照するために文字列リテラルを使用しなければならなかった前に、これは脆いツールがこれらの文字列リテラルをチェックすることを知らないため、コード要素の名前を変更する場合

受け入れられた/最高評価の回答は、すでにいくつかの優れた具体例を示しています。

4
brichins

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))]

この場合、リソースにアクセスするために生成されたプロパティさえも必要としませんでしたが、コンパイル時にリソースが存在することを確認しました。

3
Paulo Morgado

nameofの別の使用例は、インデックスをチェックする代わりにタブページをチェックすることです。以下のようにタブページのNameプロパティをチェックすることができます。

if(tabControl.SelectedTab.Name == nameof(tabSettings))
{
    // Do something
}

めちゃくちゃ少ない:)

0
diedrop

nameofキーワードの使用法の1つは、wpf でプログラム的に Bindingを設定することです。

Bindingを設定するには、Pathをstring、およびnameofキーワードで設定する必要があります。Refactorオプションを使用することは可能です。

たとえば、IsEnableUserControl依存関係プロパティがあり、それをIsEnable内のCheckBoxUserControlにバインドする場合は、次の2つのコードを使用できます。

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);

最初のコードはリファクタリングできませんが、2番目のコードはリファクタリングできません。

0
Mehdi Khademloo

あなたがASP.Net MVCを使うとき、それは利点があります。 HTMLヘルパーを使用してビュー内のコントロールを作成すると、HTML入力の名前属性にプロパティ名が使用されます。

@Html.TextBoxFor(m => m.CanBeRenamed)

それはそのようなものになります:

<input type="text" name="CanBeRenamed" />

だから今、あなたがValidateメソッドであなたのプロパティを検証する必要があるならこれを行うことができます:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
  if (IsNotValid(CanBeRenamed)) {
    yield return new ValidationResult(
      $"Property {nameof(CanBeRenamed)} is not valid",
      new [] { $"{nameof(CanBeRenamed)}" })
  }
}

あなたがリファクタリングツールを使ってあなたの資産の名前を変えても、あなたの検証は壊れません。

0
digizard

以前は以下のようなものを使用していました。

// 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()を使うことができます。

0
QtRoS