nameof()はコンパイル時に評価されますか?


114

C#6では、 nameof()演算子を、変数または型の名前を含む文字列を取得。

これはコンパイル時に評価されますか、それともいくつかのRoslyn APIを介して実行時に評価されますか?


Roslynは新しいコンパイラプラットフォームです。コンパイル時にのみ使用されます。
Paulo Morgado 2014年

2
@PauloMorgadoは真実ではありません。実行時にRosylnを使用して処理を行うことができます。ライブコードエディターの作成や、Rosylnの解析機能を使用して、木や式などで何かを実行する場合
Chris Marisic

@ChrisMarisicは私の印象ですが、トピックに関する知識が限られているため、返答しませんでした(つまり、私の質問です)。私はこの遭遇しました:scriptcs.netロスリンの力のかなり良い例である、と私は実行時のものを行うと信じているが、私はかなりそれについて十分な情報はないよ、私は間違っている可能性があります。
ジジ

@ChrisMarisic、つまり、Roslynを使用して、実行中の1つのバイナリからではなく、ソースからライブコードをビルドできるということです。また、Roslynを使用してソースをバイナリに変換し、Roslynを使用してバイナリを変更しません。実行時に絶対にRoslynを使用できない場合、コードをコンパイルすることはできません。
Paulo Morgado 2014年

回答:


119

はい。nameof()コンパイル時に評価されます。仕様の最新バージョンを見る:

nameof式は定数です。すべての場合において、nameof(...)はコンパイル時評価され、文字列を生成します。その引数は実行時に評価されず、到達不能コードと見なされます(ただし、「到達不能コード」警告は発行されません)。

から nameof演算子 -v5

このTryRoslynの例では、次のことがわかります。

public class Foo
{
    public void Bar()
    {
        Console.WriteLine(nameof(Foo));
    }
}

これにコンパイルされ、逆コンパイルされます:

public class Foo
{
    public void Bar()
    {
        Console.WriteLine("Foo");
    }
}

ランタイムに相当するものは次のとおりです。

public class Foo
{
    public void Bar()
    {
        Console.WriteLine(typeof(Foo).Name);
    }
}

コメントで述べたように、これはnameof、ジェネリック型の型パラメーターで使用する場合、型パラメーターの名前だけでなく、型パラメーターとして使用される実際の動的型の名前を取得することを期待しないことを意味します。したがって、この:

public class Foo
{
    public void Bar<T>()
    {
        Console.WriteLine(nameof(T));
    }
}

これになります:

public class Foo
{
    public void Bar<T>()
    {
        Console.WriteLine("T");
    }
}

ここで「コンパイル時」とは何ですか?MSILへのコンパイルまたはネイティブコードへのコンパイル?
user541686 2014年

6
@Mehrdad C#コンパイラはILを生成します。
i3arnon 2014年

3
簡単な質問、スイッチケースでnameofを使用できますか?
2015

2
@スペルはい
i3arnon 2015

58

@ I3arnonが提供する回答を充実させたい、コンパイル時に評価されるという証明でたのです。

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)

firstname文字列を宣言し、nameof演算子を使用すると、MSILで同じコードが生成さnameofれます。つまり、文字列変数を宣言するのと同じくらい効率的です。


4
MSILがソースコードに逆コンパイルされている場合、逆コンパイラは、それがnameof単純なハードコードされた文字列ではなく、演算子であると簡単に認識できますか?
ADTC、2014年

11
それは良い質問です!詳細な説明が必要な場合は、SOに新しい質問として投稿できます:)。ただし、簡単な答えは、逆コンパイラはそれがnameof演算子であることを理解できず、代わりに文字列リテラルを使用することです。ILSpyとReflectorの場合はそうです。
Faris Zacina 2014年

2
@ADTC:nameofは完全にload-a-string-on-the-stackに置き換えられているため、逆コンパイラは、単純な定数パラメータではなく、それがnameofであると推測することさえできますか?
ケツァルコアトル2014年

2
それは面白いね。おそらく、逆コンパイラは現在のコンテキスト(現在のメソッド/プロパティ/その他の名前)に対して文字列をチェックできます。それでも、100%信頼できる方法はありません。結局、ハードコードされた文字列を使用した可能性があります。
ジジ

2
コンパイル後にそれがnameofであるかどうかはわかりませんが、ILSpyまたはReflectorがC#6をサポートしていることはまだわかりません。ケースのthats場合は、@TheMinisterそれをテストすることはできません
ミリー・スミス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.