バージョン 6.0 には の新機能が追加nameof
されましたが、変数名を取得してコンパイル時に文字列に変更するだけなので、その目的がわかりません。
使用時に何らかの目的があるのではないかと思いましたが、使用<T>
しようとすると、使用されているタイプの代わりにnameof(T)
a が出力されます。T
目的について何か考えはありますか?
プロパティ名に基づいて例外をスローしたり、イベントを処理したりする場合など、プロパティの名前を再利用したい場合はどうでしょうかPropertyChanged
。物件名を記載したいケースが多いです。
次の例を見てください。
switch (e.PropertyName)
{
case nameof(SomeProperty):
{ break; }
// opposed to
case "SomeOtherProperty":
{ break; }
}
最初のケースではSomeProperty
、プロパティ定義と式の両方を変更しないと、名前を変更するとコンパイル エラーが発生しますnameof(SomeProperty)
。2 番目のケースでは、文字列の名前を変更SomeOtherProperty
または変更する"SomeOtherProperty"
と、ビルド時にエラーや警告が発生せずに、実行時の動作が暗黙のうちに壊れます。
これは、コードをコンパイルしてバグをなくす (一種の) ための非常に便利な方法です。
( Eric Lippert の非常に素晴らしい記事で、なぜ成功しinfoof
なかったのか、成功したのかnameof
)
nameof
C# 6.0 の機能が便利になるもう 1 つの使用例- DB の取得をより簡単にするDapperのようなライブラリを考えてみましょう。これは優れたライブラリですが、クエリ内でプロパティ/フィールド名をハードコーディングする必要があります。つまり、プロパティ/フィールドの名前を変更すると、新しいフィールド名を使用するようにクエリを更新するのを忘れる可能性が高くなります。文字列補間とnameof
機能を使用すると、コードの保守がはるかに容易になり、タイプセーフになります。
リンクにある例から
名前なし
var dog = connection.Query<Dog>(
"select Age = @Age, Id = @Id",
new {Age = (int?) null, Id = guid});
名前付き
var dog = connection.Query<Dog>(
$"select {nameof(Dog.Age)} = @Age, {nameof(Dog.Id)} = @Id",
new {Age = (int?) null, Id = guid});
私が考えることができる最も一般的な使用例は、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
。
一部のフレームワークはリフレクション マジックを使用してプロパティの名前を取得することに注意してください。
MSDN の記事には、MVC ルーティング (私にとってその概念を実際にクリックした例) がいくつか挙げられています。(フォーマットされた)説明の段落は次のとおりです。
- コードのエラーを報告するときは、
- モデル ビュー コントローラー (MVC) リンクの接続、
- プロパティ変更イベントの発火など
メソッドの文字列名を取得したいことがよく あります。nameof を使用すると、定義の名前を変更するときにコードを有効に保つことができます。
以前は文字列リテラル を使用して定義を参照する必要がありましたが、ツールはこれらの文字列リテラルをチェックすることを認識していないため、コード要素の名前を変更するときに 脆弱でした。
受け入れられた/最高評価の回答は、すでにいくつかの優れた具体例を示しています。
他の人がすでに指摘しているように、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
オペレーターを使用することをお勧めします。
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 },
}
}
nameof
キーワードの使用法の 1 つは、プログラムBinding
で wpfに設定することです。
設定するには文字列で設定する必要があり、Binding
キーワードを使用すると、Refactor オプションを使用できます。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番目のコードは...