34

私が間違っている場合は修正してください。

var typeOfName = typeof(Foo).Name;

var nameOfName = nameof(Foo);

まったく同じ出力が得られるはずです。このソースによると理解できる理由の 1 つ: https://msdn.microsoft.com/en-us/library/dn986596.aspxは、

「nameof を使用すると、定義の名前を変更するときにコードを有効に保つことができます」

クラスインスタンスを文字列として取得したい場合、そのようなことはできません:

var fooInstance = new Foo();
var nameOfName = nameof(fooInstance);

ただし、次のようなことができます。

static string GetName<T>(T item) where T : class 
{
  return typeof(T).GetProperties()[0].Name;
}
var typeOfName2 = GetName(new { fooInstance });

どちらの場合も (typeofおよびnameof) リファクタリングが可能であるため、nameof既存のものを実行するために、 などの別の上位レベルのキーワードを再発明する理由は他にありません。私がはっきりと見ていない違いはありますか?

最後に、誰かが の実装を確認するための参照ソースを教えていただければ幸いですnameof。リフレクションを使用していますか?

更新 1:ここ から取得

nameof文字列変数を宣言するのと同じくらい効率的です。反射も何もありません!

var firstname = "Gigi";
 var varname = nameof(firstname);
 Console.WriteLine(varname); // Prints "firstname" to the console

生成された MSIL をチェックアウトすると、ldstr 演算子を使用して文字列へのオブジェクト参照がスタックにプッシュされるため、文字列宣言と同等であることがわかります。

IL_0001: ldstr "Gigi"
IL_0006: stloc.0
IL_0007: ldstr "firstname"
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: call void [mscorlib]System.Console::WriteLine(string)
4

7 に答える 7

18

BenchmarkDotNet を使用したベンチマーク テストは次のとおりです。

// * Summary *

Host Process Environment Information:
BenchmarkDotNet.Core=v0.9.9.0
OS=Windows
Processor=?, ProcessorCount=8
Frequency=2740584 ticks, Resolution=364.8857 ns, Timer=TSC
CLR=CORE, Arch=64-bit ? [RyuJIT]
GC=Concurrent Workstation
dotnet cli version: 1.0.0-preview2-003133

Type=GetNameBenchmark  Mode=Throughput  LaunchCount=2
WarmupCount=10  TargetCount=200

     Method |     Median |    StdDev |
----------- |----------- |---------- |
     TypeOf | 16.0348 ns | 0.7896 ns |
     NameOf |  0.0005 ns | 0.0147 ns |
于 2017-12-20T03:58:21.907 に答える
10

Reflection を使用して文字列を生成することは可能ですが、あまり洗練されておらず、常に可能であるとは限りません。たとえば、サンドボックス化されたコードでリフレクションを使用することはできません。また、ローカル変数では使用できません。そしてそれは高価です。

演算子はnameofコンパイル時に機能します。コンパイラは、コードを解析するときに名前を既に認識しています。したがって、文字列リテラルを自明に生成できます。非常に高速で、これ以上速くなることはありません。ランタイムの制限はありません。

于 2015-11-11T11:43:50.133 に答える
6

それらの間にはいくつかの違いがありますが、主に実際的な理由があります。 例 1:

のように書くとよりエレガントです。

switch (e.ArgumentPropertyName)
{
    case nameof(aProperty):
    break;

    case "anotherProperty":
    break;
}

anotherProperty型と強打をリファクタリングしてみてください! はnameof変更を反映し、"anotherProperty"サイレントに渡され、そのケースステートメント内でコードが実行されることはありません..

例 2:

enum MetalEnum { Gold = 1,  Silver = 2, ... }

どちらがいいですか?

Console.WriteLine(MetalEnum.Gold.ToString()); // finds the name at runtime (slower)

また

Console.WriteLine(nameof(MetalEnum.Gold)); // compile time (faster)

例 3:

最後に、次のようなものを書くのがいかに醜いか覚えていますか?

PropertyChanged(this, new PropertyChangedEventArgs("Foo"));

これで、次のように美しく書くことができます。

PropertyChanged(this, new PropertyChangedEventArgs(nameof(Foo)));
于 2015-11-11T13:50:27.737 に答える
3

ドキュメントによると:

変数、型、またはメンバーの単純な (修飾されていない) 文字列名を取得するために使用されます。

...

nameofへの引数は、単純名、修飾名、メンバー アクセス、指定されたメンバーによるベース アクセス、または指定されたメンバーによるこのアクセスである必要があります。引数式はコード定義を識別しますが、評価されることはありません。

引数は構文的に式である必要があるため、列挙するのに役立たない許可されていないものが多数あります。エラーを生成するものとして言及する価値があるのは、定義済みの型 ( intvoidなど)、null 許容型 ( Point?)、配列型 ( Customer[,])、ポインター型 ( Buffer*)、修飾エイリアス ( A::B)、非バインド ジェネリック型 ( Dictionary<,>)、前処理シンボル ( DEBUG)、およびラベル ( loop:)。

nameofが取得する単純な名前は、メタデータ名ではなく、ソース名です。

したがって、このコード:

using Integer = System.Int32;
var s = "a string";
Console.WriteLine(nameof(s));
Console.WriteLine(nameof(Integer));
Console.WriteLine(nameof(System.Int32));
void M<T>() { Console.WriteLine(nameof(T)); }
M<int>();
M<string>();

印刷されます:

s
Integer
Int32
T
T
于 2015-11-11T23:45:44.793 に答える
0

Typeof は Type オブジェクトを返します。多くの場合、パラメーターとして、または変数またはフィールドとして使用されます。typeof 演算子は、Type ポインターを取得する式の一部です。

一方、Nameof は、変数の名前を含む文字列を返します。コンパイル時に機能します。これは、一部のプログラムを単純化する特別なコンパイラ機能です。

于 2015-11-11T11:58:40.437 に答える