nameofの目的は何ですか?


263

バージョン6.0にはの新機能nameofがありますが、変数名を取得してコンパイル時に文字列に変更するだけなので、目的を理解できません。

私はそれを使用するときにいくつかの目的があるかもしれないと思ったが<T>nameof(T)それをしようとするとT、使用されたタイプの代わりに私を表示するだけです。

目的について何か考えはありますか?



28
以前はそれを手に入れる方法がありませんでしたT。以前に使用されたタイプを取得する方法がありました。
Jon Hanna、

最初はやり過ぎのように見えましたが、それを使用する説得力のある理由はまだわかりません。多分MVCの例ですか?
Corey Alix 2016年

15
内で名前をリファクタリング/名前変更するときに間違いなく役立ちますnameof。タイプミスの防止にも役立ちます。
bvj

4
nameofの公式ドキュメントは次の場所に移動しました:docs.microsoft.com/en-us/dotnet/csharp/language-reference/…-質問へのかなり良い回答となる主要な使用例もリストされています。
markus s

回答:


323

プロパティ名に基づいて例外をスローしたり、PropertyChangedイベントを処理したりする場合など、プロパティ名を再利用したい場合はどうでしょうか。プロパティの名前が必要な場合が多数あります。

この例を見てみましょう:

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

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

最初のケースでは、名前SomePropertyを変更するとプロパティの名前も変更され、コンパイルが中断します。最後のケースはそうではありません。

これは、コードをコンパイルしてバグのない状態(ソート)に保つのに非常に便利な方法です。

Eric Lippertからの非常に素晴らしい記事で、なぜinfoof作れnameofなかったのか)


1
ポイントを理解し、名前をリファクタリングするときにリシャーパーが文字列を変更することを追加するだけで、VSに同様の機能があるかどうかはわかりません。
Ash Burlaczenko、2015

7
あります。しかし、ResharperとVSはどちらも、たとえばプロジェクトでは機能しません。これはします。実際、これはより良い解決策です。
Patrick Hofman、2015

49
もう1つの一般的な使用例は、MVCでのルーティングnameofと、ハードコードされた文字列ではなくアクションの名前です。
RJカスバートソン

2
@sotn質問の内容がよくわかりません。public class MyController { public ActionResult Index() { return View(nameof(Index)); } }あなたがそれを使うのを止めるようなものは何もありません-そしてあなたはnameof非静的メンバーで使うことができます(例えばあなたはnameof(MyController.Index)上記のクラスを使って呼び出すことができ、それは「インデックス」を出力します)msdn.microsoft.com/en-us/library/…で
RJ Cuthbertson

2
それが特別な理由はわかりません。変数名は常に同じですよね?インスタンスがあるかどうかにかかわらず、変数名は@sotnを変更しません
Patrick Hofman

176

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

のもう1つの使用法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....");
}

9
そして、あなたは別のクールな機能を入れました:文字列補間!
Patrick Hofman、2015

1
@PatrickHofman and typeof(T)、これは同様の状況で役立つコンパイル時の砂糖の別の部分です:-)
Keith

1
私が欠けているものの1つは、のようなものですnameofthismethod。使用できますLog.Error($"Error in {nameof(DoSomething)}...")が、これを他のメソッドにコピーして貼り付けても、まだを参照していることに気付かないでしょうDoSomething。したがって、ローカル変数またはパラメーターで完全に機能している間は、メソッド名が問題になります。
Tim Schmelter 16

3
存在nameOfする場合に[DisplayName]属性を使用するかどうか知っていますか?enum[DisplayName]がMVCプロジェクトで頻繁に使用する例
Luke T O'Brien

2
@AaronLSはい、かなり専門的であり、頻繁に使用するものではありません。しかし、それthrow newはまったく別のアンチパターンです- catch問題を修正するような感じがするため(ほとんどの場合それを非表示にしているだけ)、使いすぎはジュニア開発者に共通の問題であることがわかります。
キース

26

nameofC#6.0の機能が便利になるもう1つの使用例-DBの取得をはるかに簡単にする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 });

3
私はDapperが大好きで、文字列のインターポーレーションが本当に好きですが、IMOはこれはとても醜く見えます。列の名前を変更してクエリを壊すリスクは、このような醜いクエリに比べて非常に小さいようです。一見すると、EF LINQクエリを作成するか、[TableName]。[ColumnName]のような規則に従って、必要なときにクエリを簡単に検索/置換できると思います。
drizin

@drizin私はDapper FluentMapを使用して、このようなクエリを防止します(また、懸念の分離にも使用します)
mamuesstack

21

あなたの質問はすでに目的を表現しています。これが例外のロギングまたはスローに役立つ場合があることを確認する必要があります。

例えば。

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

これは良いことです。変数の名前を変更すると、コードが壊れるか、誤ったメッセージで例外が返されます


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

さまざまなバインディングとリフレクションの状況を考えると、さまざまな用途があります。これは、実行時エラーであったものをコンパイル時にもたらす優れた方法です。


6
@atikot:ただし、変数の名前を変更しても、コンパイラは文字列が一致しないことに気づきません。
またはMapper 2015

1
私は実際にそれを考慮に入れるresharperを使用します、しかし私はあなたの要点を見ます。
atikot 2015

4
@atikotもそうですが、Resharperはコンパイラエラーではなく警告のみを生成します。確実性と良いアドバイスには違いがあります。
Jodrell、2015

1
@atikot、および、Resharperはログメッセージをチェックしません
Jodrell

2
@ジョドレル:そして、私はそれが他のさまざまな用途もチェックしないと思う-コードビハインドで作成されたWPFバインディング、カスタムOnPropertyChangedメソッド(ではなくプロパティ名を直接受け入れるPropertyChangedEventArgs)、またはリフレクションを呼び出して特定のものを探す方法メンバーまたはタイプ?
またはMapper

13

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

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


5
これは有効な方法ですが、より便利な(そしてDRY)方法は[CallerMemberName]、新しいメソッドのparamの属性を使用してこのイベントを発生させることです。
Drew Noakes、2015

1
CallerMemberNameもすばらしいと思いますが、別のユースケースです。これは(前述のとおり)メソッドでしか使用できないためです。DRYに関しては、[CallerMemberName]string x = nullがより良いかどうかはわかりませんnameof(Property)。プロパティ名は2回使用されていると言えますが、それは基本的に関数に渡される引数です。DRYとはどういう意味かとは思いませんが:)
ロイT.

実際には、プロパティで使用できます。彼らもメンバーです。利点nameofは、プロパティセッターがプロパティ名をまったく指定する必要がないため、コピー/貼り付けのバグが発生する可能性がなくなることです。
Drew Noakes、2015

4
これはにとって「より良い」状況でありINotifyPropertyChanged、を使用[CallerMemberNameAttribute]すると、変更通知をプロパティセッターから明確に発生させるnameofことができ、構文を使用すると、コード内の別の場所から変更通知を明確に発生させることができます。
Andrew Hanlon

9

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

//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リファレンス)


7

ASP.NETコアMVCプロジェクトが使用nameofAccountController.csManageController.csRedirectToActionコントローラにアクションを参照する方法。

例:

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

これは次のように変換されます。

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

そして、ユーザーを「ホーム」コントローラの「インデックス」アクションに連れて行きます/Home/Index


まるまる食べて使ってみreturn RedirectToAction(nameof(HomeController.Index), nameof(HomeController).Substring(nameof(HomeController),0,nameof(HomeController).Length-"Controller".Length));ませんか?
Suncat2000 2017年

@ Suncat2000は、これらの処理の1つがコンパイルで行われ、他の処理が行われないためですか。:)
Dinerdo 2018

6

他の人がすでに指摘したように、 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

ただし、ソフトウェアを難読化することを計画している場合、これは欠点になる可能性があります。難読化した後、埋め込まれた文字列は要素の名前と一致しなくなる可能性があります。このテキストに依存するメカニズムは機能しなくなります。例としては、リフレクション、NotifyPropertyChangedなどがあります。

実行時に名前を決定すると、ある程度のパフォーマンスが必要になりますが、難読化しても安全です。難読化が必要でも計画でもない場合は、nameofオペレーターを使用することをお勧めします。


5

コードで変数を使用していて、変数の名前を取得する必要があることを考えて、それを印刷すると言うなら、使用する必要があります

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

そして、誰かがコードをリファクタリングし、「myVar」に別の名前を使用する場合、その人はコード内の文字列値を監視し、それに応じて変更する必要があります。

代わりに

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

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


ソースコード表現、、Typeおよび値を含む、各パラメーターに1つずつ、タプルの配列を渡す特別な変数パラメーター構文があればよかったのですが。これにより、ロギングメソッドを呼び出すコードで多くの冗長性を排除できるようになります。
スーパーキャット2015

5

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

  • コードでエラーを報告するとき、
  • model-view-controller(MVC)リンクの接続、
  • 発射特性変更イベントなど

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

以前は文字列リテラル を使用して定義を参照する必要がありましたが、ツールはこれらの文字列リテラルをチェックすることを知らないため、コード要素の名前を変更するときに 脆弱です。

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


3

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"
}

私がこれに与えてきた用途の1つは、リソースの命名です。

[Display(
    ResourceType = typeof(Resources),
    Name = nameof(Resources.Title_Name),
    ShortName = nameof(Resources.Title_ShortName),
    Description = nameof(Resources.Title_Description),
    Prompt = nameof(Resources.Title_Prompt))]

実際には、この場合、リソースにアクセスするために生成されたプロパティも必要ありませんでしたが、今ではリソースが存在することをコンパイル時にチェックしています。


0

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

設定BindingするにはPath、文字列とnameofキーワードで設定する必要があります。リファクタリングオプションを使用できます。

たとえば、にIsEnable依存関係プロパティがあり、UserControlそれをIsEnableの一部CheckBoxにバインドする場合UserControl、次の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

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

// 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

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

のもう1つの使用例はnameof、インデックスをチェックする代わりに、タブページをチェックすることです。Nameプロパティを:

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

より面倒な:)


0

私はそれを見つけるnameof私のアプリケーションの増加は非常に長いの読みやすさと複雑なSQL文を。これにより、変数が文字列の海から目立つようになり、SQLステートメントで変数が使用されている場所を特定する作業が不要になります。

public bool IsFooAFoo(string foo, string bar)
{
    var aVeryLongAndComplexQuery = $@"SELECT yada, yada
    -- long query in here
    WHERE fooColumn = @{nameof(foo)}
    AND barColumn = @{nameof(bar)}
    -- long query here";


    SqlParameter[] parameters = {
        new SqlParameter(nameof(foo), SqlDBType.VarChar, 10){ Value = foo },
        new SqlParameter(nameof(bar), SqlDBType.VarChar, 10){ Value = bar },
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.