nameof ()는 컴파일 타임에 평가됩니까?


114

C # 6에서는 nameof()연산자를 사용하여 변수 또는 형식의 이름이 포함 된 문자열을 가져올 수 있습니다 .

이것은 컴파일 타임에 평가됩니까, 아니면 일부 Roslyn API를 통해 런타임에 평가됩니까?


Roslyn은 새로운 컴파일러 플랫폼입니다. 컴파일 타임에만 사용됩니다.
Paulo Morgado

2
@PauloMorgado는 사실이 아닙니다. 런타임에 Rosyln을 사용하여 작업을 수행 할 수 있습니다. 이러한 라이브 코드 편집기를 구축하거나 나무 또는 표현이나 뭔가 일 할 Rosyln의 구문 분석 물건을 사용하는 등
크리스 Marisic

@ChrisMarisic은 내 인상이지만 주제에 대한 지식이 제한되어 있기 때문에 응답하지 않았습니다 (따라서 내 질문). 나는 이것을 발견했다 : scriptcs.net 은 Roslyn의 힘의 꽤 좋은 예이며, 런타임 작업을한다고 생각하지만, 그것에 대해 잘 알지 못하기 때문에 틀릴 수 있습니다.
Gigi

@ChrisMarisic, 그래서 당신이 말하는 것은 Roslyn을 사용하여 실행중인 하나의 바이너리가 아닌 소스에서 라이브 코드를 빌드 할 수 있다는 것입니다. 그리고 여전히 Roslyn을 사용하여 소스를 Roslyn을 사용하여 thos 바이너리를 변경하지 않는 바이너리로 변환하고 있습니다. 런타임에 Roslyn을 절대적으로 사용할 수 없다면 코드를 컴파일 할 수 없습니다.
Paulo Morgado

답변:


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

6
@Mehrdad C # 컴파일러는 IL을 생성합니다.
i3arnon 2014 년

3
빠른 질문, 스위치 케이스에 nameof를 사용할 수 있습니까?
Spell

2
@Spell Yes
i3arnon jul.

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-to-the-stack으로 완전히 바뀌었을 때, 디 컴파일러는 그것을 단순한 상수 매개 변수가 아닌 nameof라고 추측하려고 시도 할 수 있습니까?
quetzalcoatl 2014 년

2
그것 참 흥미 롭네. 아마도 디 컴파일러는 현재 컨텍스트 (사용자가 속한 메서드 / 속성 / 등의 이름)에 대해 문자열을 확인할 수 있습니다. 그래도 100 % 신뢰할 수있는 방법은 없습니다. 결국 하드 코딩 된 문자열을 사용했을 수 있습니다.
Gigi

2
컴파일 후 이름인지 알 수 없다는 데 동의하지만 ILSpy 또는 Reflector가 C # 6을 지원한다는 징후는 아직 보이지 않습니다. 이 경우 @TheMinister
Millie Smith
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.