nameof () ได้รับการประเมินตามเวลาคอมไพล์หรือไม่


114

ใน C # 6 คุณสามารถใช้ตัวnameof()ดำเนินการเพื่อรับสตริงที่มีชื่อของตัวแปรหรือประเภท

สิ่งนี้ได้รับการประเมินในเวลาคอมไพล์หรือรันไทม์ผ่าน Roslyn API บางตัว?


Roslyn เป็นแพลตฟอร์มคอมไพเลอร์ใหม่ ใช้ในเวลาคอมไพล์เท่านั้น
Paulo Morgado

2
@PauloMorgado ไม่เป็นความจริงคุณสามารถใช้ Rosyln ในเวลาทำงานเพื่อทำสิ่งต่างๆ เช่นการสร้างโปรแกรมแก้ไขโค้ดสดหรือใช้การแยกวิเคราะห์ของ Rosyln เพื่อทำสิ่งต่างๆกับต้นไม้หรือนิพจน์หรืออะไรบางอย่าง
Chris Marisic

@ChrisMarisic นั่นคือความประทับใจของฉัน แต่ฉันไม่ได้ตอบกลับเนื่องจากความรู้ในหัวข้อมี จำกัด (ดังนั้นคำถามของฉัน) ฉันเจอสิ่งนี้: scriptcs.netซึ่งเป็นตัวอย่างที่ดีของพลังของ Roslyn และฉันเชื่อว่าเป็นสิ่งที่รันไทม์ แต่ฉันคิดผิดเพราะฉันไม่ค่อยรู้เรื่องนี้
Gigi

@ChrisMarisic ดังนั้นสิ่งที่คุณพูดคือคุณสามารถใช้ Roslyn เพื่อสร้างโค้ดสดจากซอร์สไม่ใช่จากไบนารีเดียวที่กำลังทำงานอยู่ และคุณยังคงใช้ Roslyn เพื่อเปลี่ยนแหล่งที่มาเป็นไบนารีที่เคยชินกับ Roslyn เพื่อเปลี่ยน thos binries หากคุณไม่สามารถใช้ Roslyn ในรันไทม์ได้อย่างแท้จริงคุณจะไม่สามารถรวบรวมโค้ดใด ๆ ได้
Paulo Morgado

คำตอบ:


119

ใช่. nameof()ได้รับการประเมินตามเวลาคอมไพล์ ดูข้อมูลจำเพาะเวอร์ชันล่าสุด:

นิพจน์ nameof เป็นค่าคงที่ ในทุกกรณี nameof (... ) จะถูกประเมินในเวลาคอมไพล์เพื่อสร้างสตริง อาร์กิวเมนต์ของมันไม่ได้รับการประเมินที่รันไทม์และถือว่าเป็นโค้ดที่ไม่สามารถเข้าถึงได้ (อย่างไรก็ตามจะไม่แสดงคำเตือน "โค้ดที่ไม่สามารถเข้าถึงได้")

จากตัวดำเนินการ nameof - v5.0

คุณจะเห็นได้จากตัวอย่าง 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

3
คำถามด่วนฉันสามารถใช้ nameof ในเคสสวิตช์ได้หรือไม่?
คาถา

2
@Spell Yes
i3arnon

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)

คุณจะสังเกตเห็นว่าการประกาศสตริงชื่อแรกและการใช้ตัวnameofดำเนินการสร้างรหัสเดียวกันใน MSIL ซึ่งหมายความnameofว่ามีประสิทธิภาพเทียบเท่ากับการประกาศตัวแปรสตริง


4
หาก MSIL ถูกถอดรหัสเป็นซอร์สโค้ดจะง่ายเพียงใดที่ผู้ถอดรหัสจะรับรู้ว่าเป็นตัวnameofดำเนินการไม่ใช่สตริงฮาร์ดโค้ดธรรมดา
ADTC

11
นั่นเป็นคำถามที่ดี! คุณสามารถโพสต์เป็นคำถามใหม่ใน SO ได้หากต้องการคำอธิบายโดยละเอียด :) .. อย่างไรก็ตามคำตอบสั้น ๆ คือ decompiler จะไม่สามารถระบุได้ว่าเป็นตัวดำเนินการ nameof แต่จะใช้สตริงตามตัวอักษรแทน . ฉันได้ตรวจสอบแล้วว่าเป็นกรณีของ ILSpy และ Reflector
Faris Zacina

2
@ADTC: เนื่องจาก nameof ถูกแทนที่ด้วย load-a-string-into-the-stack อย่างสมบูรณ์ decompiler จะพยายามเดาได้อย่างไรว่าเป็น nameof ไม่ใช่พารามิเตอร์คงที่ง่ายๆ
quetzalcoatl

2
นั่นน่าสนใจ. บางที decompiler อาจตรวจสอบสตริงกับบริบทปัจจุบัน (ชื่อของ method / property / etc ที่คุณอยู่) ถึงกระนั้นก็ไม่มีทางที่จะเชื่อถือได้ 100% - คุณอาจใช้สตริงแบบฮาร์ดโค้ดไปแล้ว
Gigi

2
แม้ว่าฉันยอมรับว่าคุณไม่สามารถรู้ได้ว่าเป็นชื่อของฉันหลังจากรวบรวม แต่ฉันไม่เห็นข้อบ่งชี้ใด ๆ ว่า ILSpy หรือตัวสะท้อนแสงรองรับ C # 6 ถ้าเป็นอย่างนั้นก็ทดสอบไม่ได้ @ TheMinister
Millie Smith
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.