Nameof () viene valutato in fase di compilazione?


114

In C # 6 è possibile utilizzare l' nameof()operatore per ottenere una stringa contenente il nome di una variabile o di un tipo.

Viene valutato in fase di compilazione o in fase di esecuzione tramite alcune API Roslyn?


Roslyn è la nuova piattaforma del compilatore. Viene utilizzato solo in fase di compilazione.
Paulo Morgado

2
@PauloMorgado non è vero, puoi usare Rosyln in fase di esecuzione per fare le cose. Come costruire un editor di codice live o utilizzare le funzioni di analisi di Rosyln per fare cose con alberi o espressioni o qualcosa del genere
Chris Marisic

@ChrisMarisic questa è la mia impressione, ma non ho risposto poiché la mia conoscenza sull'argomento è limitata (da qui la mia domanda). Mi sono imbattuto in questo: scriptcs.net che è un ottimo esempio del potere di Roslyn e che credo faccia cose di runtime, ma potrei sbagliarmi perché non sono abbastanza ben informato al riguardo.
Gigi

@ChrisMarisic, quindi, quello che stai dicendo è che puoi usare Roslyn per creare codice live dal sorgente, non dall'unico binario in esecuzione. E stai ancora usando Roslyn per trasformare i sorgenti in binari che non useranno Roslyn per cambiare questi binari. Se non puoi usare assolutamente Roslyn in fase di esecuzione, non potresti mai compilare alcun codice.
Paulo Morgado

Risposte:


119

Sì. nameof()viene valutato in fase di compilazione. Guardando l'ultima versione delle specifiche:

Il nome dell'espressione è una costante. In tutti i casi, nameof (...) viene valutato in fase di compilazione per produrre una stringa. Il suo argomento non viene valutato in fase di runtime ed è considerato codice non raggiungibile (tuttavia non emette un avviso di "codice non raggiungibile").

Da nome dell'operatore - v5

Puoi vederlo con questo esempio di TryRoslyn dove questo:

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

Viene compilato e decompilato in questo:

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

Il suo equivalente in fase di esecuzione è:

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

Come accennato nei commenti, ciò significa che quando si utilizzano nameofparametri di tipo in un tipo generico, non aspettarsi di ottenere il nome del tipo dinamico effettivo utilizzato come parametro di tipo invece del solo nome del parametro di tipo. Così questo:

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

Diventerà questo:

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

Che cos'è il "tempo di compilazione" qui? Compilazione in MSIL o compilazione in codice nativo?
user541686

6
@Mehrdad Il compilatore C # genera IL.
i3arnon

3
Domanda veloce, posso usare nameof in un caso switch?
Spell

2
@Spell Yes
i3arnon

58

Volevo arricchire la risposta fornita da @ I3arnon con una prova che viene valutata in fase di compilazione.

Supponiamo che io voglia stampare il nome di una variabile nella Console utilizzando l' nameofoperatore:

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

Quando controlli l'MSIL generato, vedrai che è equivalente a una dichiarazione di stringa perché un riferimento a un oggetto a una stringa viene inserito nello stack utilizzando l' ldstroperatore:

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)

Noterai che la dichiarazione della stringa firstname e l'utilizzo nameofdell'operatore genera lo stesso codice in MSIL, il che significa che nameofè efficiente quanto la dichiarazione di una variabile stringa.


4
Se MSIL viene decompilato in codice sorgente, quanto sarà facile per il decompilatore riconoscere che era un nameofoperatore, non una semplice stringa hardcoded?
ADTC

11
Questa è una buona domanda! puoi postarlo come nuova domanda su SO se vuoi ottenere una spiegazione dettagliata :) .. tuttavia la risposta breve è che il decompilatore non sarà in grado di capire che era un operatore nameof, ma utilizzerà invece una stringa letterale . Ho verificato che è il caso di ILSpy e Reflector.
Faris Zacina

2
@ADTC: Dato che nameof è completamente sostituito con load-a-string-on-the-stack, come potrebbe il decompilatore tentare di indovinare che era un nameof e non un semplice parametro costante?
quetzalcoatl

2
È interessante. Forse il decompilatore potrebbe controllare la stringa rispetto al contesto corrente (nome del metodo / proprietà / ecc. In cui ti trovi). Tuttavia, non c'è modo che sia affidabile al 100%: dopotutto potresti aver usato una stringa codificata.
Gigi

2
Anche se sono d'accordo sul fatto che non si può sapere se è un nome dopo la compilazione, non vedo alcuna indicazione che ILSpy o Reflector supportino ancora C # 6. Se è così, non puoi provarlo @TheMinister
Millie Smith,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.