バージョン6.0にはの新機能nameof
がありますが、変数名を取得してコンパイル時に文字列に変更するだけなので、目的を理解できません。
私はそれを使用するときにいくつかの目的があるかもしれないと思ったが<T>
、nameof(T)
それをしようとするとT
、使用されたタイプの代わりに私を表示するだけです。
目的について何か考えはありますか?
T
。以前に使用されたタイプを取得する方法がありました。
nameof
。タイプミスの防止にも役立ちます。
バージョン6.0にはの新機能nameof
がありますが、変数名を取得してコンパイル時に文字列に変更するだけなので、目的を理解できません。
私はそれを使用するときにいくつかの目的があるかもしれないと思ったが<T>
、nameof(T)
それをしようとするとT
、使用されたタイプの代わりに私を表示するだけです。
目的について何か考えはありますか?
T
。以前に使用されたタイプを取得する方法がありました。
nameof
。タイプミスの防止にも役立ちます。
回答:
プロパティ名に基づいて例外をスローしたり、PropertyChanged
イベントを処理したりする場合など、プロパティ名を再利用したい場合はどうでしょうか。プロパティの名前が必要な場合が多数あります。
この例を見てみましょう:
switch (e.PropertyName)
{
case nameof(SomeProperty):
{ break; }
// opposed to
case "SomeOtherProperty":
{ break; }
}
最初のケースでは、名前SomeProperty
を変更するとプロパティの名前も変更され、コンパイルが中断します。最後のケースはそうではありません。
これは、コードをコンパイルしてバグのない状態(ソート)に保つのに非常に便利な方法です。
(Eric Lippertからの非常に素晴らしい記事で、なぜinfoof
作れnameof
なかったのか)
nameof
と、ハードコードされた文字列ではなくアクションの名前です。
public class MyController { public ActionResult Index() { return View(nameof(Index)); } }
あなたがそれを使うのを止めるようなものは何もありません-そしてあなたはnameof
非静的メンバーで使うことができます(例えばあなたはnameof(MyController.Index)
上記のクラスを使って呼び出すことができ、それは「インデックス」を出力します)msdn.microsoft.com/en-us/library/…で
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....");
}
typeof(T)
、これは同様の状況で役立つコンパイル時の砂糖の別の部分です:-)
nameofthismethod
。使用できますLog.Error($"Error in {nameof(DoSomething)}...")
が、これを他のメソッドにコピーして貼り付けても、まだを参照していることに気付かないでしょうDoSomething
。したがって、ローカル変数またはパラメーターで完全に機能している間は、メソッド名が問題になります。
nameOf
する場合に[DisplayName]
属性を使用するかどうか知っていますか?enum
私[DisplayName]
がMVCプロジェクトで頻繁に使用する例
throw new
はまったく別のアンチパターンです- catch
問題を修正するような感じがするため(ほとんどの場合それを非表示にしているだけ)、使いすぎはジュニア開発者に共通の問題であることがわかります。
nameof
C#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 });
あなたの質問はすでに目的を表現しています。これが例外のロギングまたはスローに役立つ場合があることを確認する必要があります。
例えば。
public void DoStuff(object input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
}
これは良いことです。変数の名前を変更すると、コードが壊れるか、誤ったメッセージで例外が返されます。
もちろん、用途はこの単純な状況に限定されません。nameof
変数またはプロパティの名前をコード化すると便利なときにいつでも使用できます。
さまざまなバインディングとリフレクションの状況を考えると、さまざまな用途があります。これは、実行時エラーであったものをコンパイル時にもたらす優れた方法です。
OnPropertyChanged
メソッド(ではなくプロパティ名を直接受け入れるPropertyChangedEventArgs
)、またはリフレクションを呼び出して特定のものを探す方法メンバーまたはタイプ?
私が考えることができる最も一般的なユースケースは、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があることに注意してください。これはもう必要ありません。
[CallerMemberName]
、新しいメソッドのparamの属性を使用してこのイベントを発生させることです。
[CallerMemberName]string x = null
がより良いかどうかはわかりませんnameof(Property)
。プロパティ名は2回使用されていると言えますが、それは基本的に関数に渡される引数です。DRYとはどういう意味かとは思いませんが:)
nameof
は、プロパティセッターがプロパティ名をまったく指定する必要がないため、コピー/貼り付けのバグが発生する可能性がなくなることです。
INotifyPropertyChanged
、を使用[CallerMemberNameAttribute]
すると、変更通知をプロパティセッターから明確に発生させる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あなたはそのことについて心配する必要はありません。
ASP.NETコアMVCプロジェクトが使用nameof
中AccountController.cs
とManageController.cs
でRedirectToAction
コントローラにアクションを参照する方法。
例:
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));
ませんか?
他の人がすでに指摘したように、 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
オペレーターを使用することをお勧めします。
コードで変数を使用していて、変数の名前を取得する必要があることを考えて、それを印刷すると言うなら、使用する必要があります
int myVar = 10;
print("myVar" + " value is " + myVar.toString());
そして、誰かがコードをリファクタリングし、「myVar」に別の名前を使用する場合、その人はコード内の文字列値を監視し、それに応じて変更する必要があります。
代わりに
print(nameof(myVar) + " value is " + myVar.toString());
自動的にリファクタリングするのに役立ちます!
Type
および値を含む、各パラメーターに1つずつ、タプルの配列を渡す特別な変数パラメーター構文があればよかったのですが。これにより、ロギングメソッドを呼び出すコードで多くの冗長性を排除できるようになります。
MSDNの記事には、MVCルーティング(実際にこのコンセプトをクリックした例)がいくつかリストされています。(フォーマットされた)説明の段落は次のとおりです。
- コードでエラーを報告するとき、
- model-view-controller(MVC)リンクの接続、
- 発射特性変更イベントなど
メソッドの文字列名をキャプチャしたいことがよくあります 。nameofを使用すると、定義の名前を変更するときにコードを有効に保つことができます。
以前は文字列リテラル を使用して定義を参照する必要がありましたが、ツールはこれらの文字列リテラルをチェックすることを知らないため、コード要素の名前を変更するときに 脆弱です。
受け入れられた/最高評価の回答はすでにいくつかの優れた具体例を示しています。
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))]
実際には、この場合、リソースにアクセスするために生成されたプロパティも必要ありませんでしたが、今ではリソースが存在することをコンパイル時にチェックしています。
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番目のコードは...
以前はそのようなものを使用していました:
// 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()を使用できます。
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)}" })
}
}
リファクタリングツールを使用してプロパティの名前を変更した場合でも、検証は失敗しません。
私はそれを見つける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 },
}
}