คุณสามารถทำอะไรใน MSIL ที่คุณไม่สามารถทำได้ใน C # หรือ VB.NET [ปิด]


165

รหัสทั้งหมดที่เขียนใน. NET ภาษารวบรวม MSIL แต่มีงานเฉพาะ / การดำเนินงานที่คุณสามารถทำได้เพียงใช้ MSIL โดยตรงหรือไม่

ให้เราทำสิ่งต่าง ๆ ได้ง่ายขึ้นใน MSIL กว่า C #, VB.NET, F #, j # หรือภาษา NET อื่น ๆ

จนถึงตอนนี้เรามีสิ่งนี้:

  1. หางเรียกซ้ำ
  2. Generic Co / Contravariance
  3. เกินพิกัดที่แตกต่างกันเฉพาะในประเภทผลตอบแทน
  4. แทนที่ตัวดัดแปลงการเข้าถึง
  5. มีคลาสที่ไม่สามารถสืบทอดจาก System.Object
  6. ข้อยกเว้นที่กรอง (สามารถทำได้ใน vb.net)
  7. การเรียกใช้วิธีเสมือนของชนิดคลาสคงที่ปัจจุบัน
  8. รับการจัดการกับชนิดของค่าชนิดบรรจุกล่อง
  9. ลอง / ผิด
  10. การใช้ชื่อต้องห้าม
  11. กำหนดก่อสร้าง parameterless ของคุณเองสำหรับประเภทค่า
  12. กำหนดกิจกรรมด้วยraiseองค์ประกอบ
  13. การแปลงบางอย่างได้รับอนุญาตจาก CLR แต่ไม่ใช่โดย C #
  14. ทำให้ไม่ใช่วิธีการที่เป็นmain().entrypoint
  15. ทำงานกับชนพื้นเมืองintและunsigned intประเภทพื้นเมืองโดยตรง
  16. เล่นกับตัวชี้ชั่วคราว
  17. คำสั่ง emitbyte ใน MethodBodyItem
  18. โยนและจับระบบที่ไม่ใช่ประเภทข้อยกเว้น
  19. รับช่วง Enums (ไม่ได้ยืนยัน)
  20. คุณสามารถจัดการกับอาร์เรย์ของไบต์เป็นอาร์เรย์ (ขนาดเล็ก 4x) ของ ints
  21. คุณสามารถมีฟิลด์ / วิธี / คุณสมบัติ / เหตุการณ์ทั้งหมดมีชื่อเดียวกัน (ไม่ได้รับการยืนยัน)
  22. คุณสามารถแยกสาขากลับเป็นบล็อกลองได้จากบล็อก catch ของมันเอง
  23. คุณสามารถเข้าถึงตัวระบุการเข้าถึง famandassem ( protected internalคือ fam หรือ assem)
  24. เข้าถึง<Module>ชั้นเรียนโดยตรงเพื่อกำหนดฟังก์ชั่นทั่วโลกหรือโมดูลเริ่มต้น

17
คำถามยอดเยี่ยม!
Tamas Czinege

5
F # รองรับการเรียกซ้ำแบบหางดู: en.wikibooks.org/wiki/F_Sharp_Programming/Recursion
Bas Bossink

4
รับช่วง enums หรือไม่ นั่นอาจจะเป็นสิ่งที่ดีมาก ..
จิมมี่ฮอฟฟา

1
วิธีการหลักมีทุน M ใน. NET
Concrete Gannet

4
การอ้างสิทธิ์แบบ "ปิดเป็นแบบไม่สร้างสรรค์" นั้นไร้สาระ นี่เป็นคำถามเชิงประจักษ์
Jim Balter

คำตอบ:


34

MSIL อนุญาตให้โอเวอร์โหลดที่แตกต่างกันในประเภทส่งคืนเท่านั้นเนื่องจาก

call void [mscorlib]System.Console::Write(string)

หรือ

callvirt int32 ...

5
คุณรู้จักสิ่งของประเภทนี้ได้อย่างไร :)
Gerrie Schenck


8
นี่มันเจ๋งมาก. ใครที่ไม่ต้องการให้ผลตอบแทนเกินพิกัด?
Jimmy Hoffa

12
หากทั้งสองวิธีนั้นเหมือนกันยกเว้นเป็นประเภทส่งคืนสามารถเรียกจาก C # หรือ vb.net ได้หรือไม่
supercat

29

ภาษา. Net ส่วนใหญ่รวมถึง C # และ VB ไม่ได้ใช้คุณสมบัติเรียกซ้ำหางของรหัส MSIL

การเรียกซ้ำแบบหางเป็นการเพิ่มประสิทธิภาพที่พบได้ทั่วไปในภาษาที่ใช้งานได้ มันเกิดขึ้นเมื่อเมธอด A สิ้นสุดลงโดยส่งคืนค่าของเมธอด B เช่นนั้นสแต็กของเมธอด A สามารถถูกจัดสรรคืนได้เมื่อทำการเรียกเมธอด B

รหัส MSIL รองรับการเรียกซ้ำหางอย่างชัดเจนและสำหรับอัลกอริทึมบางอย่างนี่อาจเป็นการเพิ่มประสิทธิภาพที่สำคัญในการทำ แต่เนื่องจาก C # และ VB ไม่ได้สร้างคำแนะนำในการทำสิ่งนี้จึงต้องทำด้วยตนเอง (หรือใช้ F # หรือภาษาอื่น ๆ )

นี่คือตัวอย่างของวิธีเรียกใช้การเรียกซ้ำแบบหางด้วยตนเองใน C #:

private static int RecursiveMethod(int myParameter)
{
    // Body of recursive method
    if (BaseCase(details))
        return result;
    // ...

    return RecursiveMethod(modifiedParameter);
}

// Is transformed into:

private static int RecursiveMethod(int myParameter)
{
    while (true)
    {
        // Body of recursive method
        if (BaseCase(details))
            return result;
        // ...

        myParameter = modifiedParameter;
    }
}

เป็นเรื่องปกติที่จะลบการสอบถามซ้ำโดยการย้ายข้อมูลโลคัลจากสแต็กฮาร์ดแวร์ไปยังโครงสร้างข้อมูลสแต็กที่จัดสรรฮีป ในการกำจัดการเรียกซ้ำแบบ tail-call ดังแสดงด้านบนสแต็กจะถูกกำจัดออกอย่างสมบูรณ์ซึ่งเป็นการปรับให้เหมาะสมที่ดี นอกจากนี้ค่าส่งคืนไม่จำเป็นต้องเดินขึ้นสายคอลยาว แต่จะถูกส่งกลับโดยตรง

แต่อย่างไรก็ตาม CIL ให้คุณสมบัตินี้เป็นส่วนหนึ่งของภาษา แต่ด้วย C # หรือ VB จะต้องดำเนินการด้วยตนเอง (กระวนกระวายใจยังมีอิสระที่จะทำให้การเพิ่มประสิทธิภาพนี้ด้วยตัวเอง แต่นั่นเป็นปัญหาอื่น ๆ ทั้งหมด)


1
F # ไม่ได้ใช้การเรียกซ้ำแบบหางของ MSIL เนื่องจากจะใช้งานได้ในกรณีที่เชื่อถือได้ (CAS) เท่านั้นเนื่องจากวิธีการที่ไม่ปล่อยให้สแต็กตรวจสอบ assrtions การอนุญาต (ฯลฯ )
ริชาร์ด

10
Richard ฉันไม่แน่ใจว่าคุณหมายถึงอะไร F # ปล่อยหางอย่างแน่นอน คำนำหน้าโทรสวยมากทั่วทุกสถานที่ ตรวจสอบ IL สำหรับสิ่งนี้: "let print x = print_any x"
MichaelGG

1
ฉันเชื่อว่า JIT จะใช้การเรียกซ้ำแบบหางในบางกรณี - และในบางกรณีจะไม่สนใจคำขอที่ชัดเจน ขึ้นอยู่กับสถาปัตยกรรมของโปรเซสเซอร์ IIRC
Jon Skeet

3
@Abel: ในขณะที่สถาปัตยกรรมโพรเซสเซอร์ไม่เกี่ยวข้องในทางทฤษฎีแต่ก็ไม่ได้เกี่ยวข้องกันในทางปฏิบัติเนื่องจาก JIT ที่แตกต่างกันสำหรับสถาปัตยกรรมที่แตกต่างกันมีกฎที่แตกต่างกันสำหรับการเรียกซ้ำแบบหางใน. NET คุณสามารถมีโปรแกรมที่เป่าขึ้นบน x86 ได้อย่างง่ายดายแต่ไม่ใช่ใน x64 เพียงเพราะหาง recursion สามารถจะดำเนินการในทั้งสองกรณีไม่ได้หมายความว่าเป็น โปรดทราบว่าคำถามนี้เกี่ยวกับ. NET โดยเฉพาะ
Jon Skeet

2
C # ไม่จริงโทรหางภายใต้ x64 ในกรณีที่เฉพาะเจาะจง: community.bartdesmet.net/blogs/bart/archive/2010/07/07/...
Pieter van Ginkel

21

ใน MSIL คุณสามารถมีคลาสที่ไม่สามารถสืบทอดจาก System.Object

โค้ดตัวอย่าง: คอมไพล์ด้วย ilasm.exe UPDATE:คุณต้องใช้ "/ NOAUTOINHERIT" เพื่อป้องกันแอสเซมเบลอร์ไม่ให้สืบทอดโดยอัตโนมัติ

// Metadata version: v2.0.50215
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 2:0:0:0
}
.assembly sample
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module sample.exe
// MVID: {A224F460-A049-4A03-9E71-80A36DBBBCD3}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x02F20000


// =============== CLASS MEMBERS DECLARATION ===================

.class public auto ansi beforefieldinit Hello
{
  .method public hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    // Code size       13 (0xd)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "Hello World!"
    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  ret
  } // end of method Hello::Main
} // end of class Hello

2
@Jon Skeet - ด้วยความเคารพคุณสามารถช่วยฉันเข้าใจความหมายของ NOAUTOINHERIT ได้ไหม MSDN ระบุ "ปิดใช้งานการสืบทอดเริ่มต้นจากวัตถุเมื่อไม่มีการระบุคลาสพื้นฐานใหม่ใน. NET Framework รุ่น 2.0"
Ramesh

2
@Michael - คำถามเกี่ยวกับ MSIL ไม่ใช่ภาษากลางระดับกลาง ฉันยอมรับสิ่งนี้อาจเป็นไปไม่ได้ใน CIL แต่ก็ยังใช้งานได้กับ MSIL
Ramesh

4
@Ramesh: อ๊ะคุณพูดถูกแล้ว ฉันจะบอกว่า ณ จุดนี้มันทำลายข้อกำหนดมาตรฐานและไม่ควรใช้ ตัวสะท้อนแสงไม่ได้โหลด assmebly อย่างไรก็ตามมันสามารถทำได้ด้วยอุ้งเชิงกราน ฉันสงสัยว่าทำไมบนโลกถึงอยู่ที่นั่น
Jon Skeet

4
(อาฉันเห็น / noautoinherit บิตถูกเพิ่มเข้ามาหลังจากที่ความคิดเห็นของฉันอย่างน้อยผมรู้สึกค่อนข้างดีเกี่ยวกับการไม่ทราบว่ามันมาก่อน ... .)
จอนสกีต

1
ฉันจะเพิ่มที่อย่างน้อยใน. NET 4.5.2 บน Windows มันรวบรวม แต่ไม่ได้ดำเนินการ ( TypeLoadException) PEVerify ส่งคืน: [MD]: ข้อผิดพลาด: TypeDef ที่ไม่ใช่ส่วนต่อประสานและไม่ใช่คลาสวัตถุที่ขยายโทเค็น Nil
xanatos

20

เป็นไปได้ที่จะรวมprotectedและinternalตัวดัดแปลงการเข้าถึง ใน C # ถ้าคุณเขียนprotected internalสมาชิกสามารถเข้าถึงได้จากแอสเซมบลีและจากคลาสที่ได้รับ Via MSIL คุณจะได้รับเป็นสมาชิกที่สามารถเข้าถึงได้จากชั้นเรียนมาในการชุมนุมเท่านั้น (ฉันคิดว่ามันอาจมีประโยชน์ทีเดียว!)


4
ตอนนี้ผู้สมัครจะต้องดำเนินการใน C # 7.1 ( github.com/dotnet/csharplang/issues/37 ) ตัวแก้ไขการเข้าถึงคือprivate protected
Happypig375

5
วางจำหน่ายเป็นส่วนหนึ่งของ C # 7.2: blogs.msdn.microsoft.com/dotnet/2017/11/15/…
Joe Sewell

18

Ooh ฉันไม่ได้เห็นสิ่งนี้ในเวลา (ถ้าคุณเพิ่มแท็ก jon-skeet มีโอกาสมากขึ้น แต่ฉันไม่ได้ตรวจสอบบ่อยครั้ง)

ดูเหมือนว่าคุณจะได้คำตอบที่ดีอยู่แล้ว นอกจากนี้:

  • คุณไม่สามารถรับหมายเลขอ้างอิงในประเภทค่าชนิดบรรจุกล่องใน C # คุณสามารถใน C ++ / CLI
  • คุณไม่สามารถลอง / ข้อผิดพลาดใน C # ("ความผิด" เป็นเหมือน "จับทุกอย่างและทำใหม่ในตอนท้ายของบล็อก" หรือ "ในที่สุด แต่ในความล้มเหลวเท่านั้น")
  • มีชื่อมากมายที่ถูกห้ามใช้โดย C # แต่เป็นกฎหมาย IL
  • IL ช่วยให้คุณสามารถกำหนดก่อสร้าง parameterless ของคุณเองสำหรับประเภทค่า
  • คุณไม่สามารถกำหนดกิจกรรมด้วยองค์ประกอบ "เพิ่ม" ใน C # (ใน VB คุณต้องใช้สำหรับเหตุการณ์ที่กำหนดเอง แต่เหตุการณ์ "ค่าเริ่มต้น" จะไม่รวมหนึ่งเหตุการณ์)
  • การแปลงบางอย่างได้รับอนุญาตจาก CLR แต่ไม่ใช่ C # หากคุณผ่านobjectใน C # บางครั้งสิ่งเหล่านี้จะใช้ได้ ดูuint [] / int [] คำถาม SOสำหรับตัวอย่าง

ฉันจะเพิ่มสิ่งนี้ถ้าฉันคิดอย่างอื่น ...


3
Ah แท็ก jon-skeet ฉันรู้ว่าฉันพลาดอะไรบางอย่างไป!
Binoj Antony

ในการใช้ชื่อตัวระบุที่ผิดกฎหมายคุณสามารถใส่คำนำหน้าด้วย @ ใน C #
George Polevoy

4
@George: ใช้งานได้กับคำหลัก แต่ไม่ใช่ชื่อ IL ที่ถูกต้องทั้งหมด ลองระบุ<>aเป็นชื่อใน C # ...
Jon Skeet


14

ใน IL คุณสามารถโยนและจับได้ทุกประเภทไม่เพียง แต่มาจากประเภทSystem.Exceptionใด


6
คุณสามารถทำได้ใน C # ด้วยเมื่อมีtry/ catchไม่มีวงเล็บในคำสั่ง catch คุณจะได้รับข้อยกเว้นที่ไม่เหมือนข้อยกเว้นเช่นกัน โยน Exceptionแต่เป็นไปได้แน่นอนเฉพาะเมื่อคุณได้รับมรดกจาก
Abel

@bel คุณแทบจะไม่สามารถพูดได้ว่าคุณกำลังจับอะไรบางอย่างถ้าคุณไม่สามารถอ้างถึงมัน
Jim Balter

2
@JimBalter ถ้าคุณไม่จับมันแอปพลิเคชันก็จะขัดข้อง หากคุณจับได้แอปพลิเคชันจะไม่ผิดพลาด ดังนั้นการอ้างถึงวัตถุข้อยกเว้นจึงแตกต่างจากการจับมัน
Daniel Earwicker

ฮ่า ๆ! ความแตกต่างระหว่างแอปที่ยกเลิกหรือต่อเนื่องเป็นเรื่องที่โอ้อวด? ตอนนี้ฉันคิดว่าฉันอาจได้ยินทุกอย่าง
Daniel Earwicker

น่าสนใจเพียงพอ CLR ไม่อนุญาตให้คุณทำเช่นนี้อีกต่อไป โดยค่าเริ่มต้นก็จะห่อวัตถุที่ไม่ใช่ข้อยกเว้นในRuntimeWrappedException
Jwosty

10

IL มีความแตกต่างระหว่างcallและcallvirtสำหรับวิธีการโทรเสมือน ด้วยการใช้แบบเดิมคุณสามารถบังคับให้เรียกวิธีเสมือนของชนิดคลาสคงที่ปัจจุบันแทนฟังก์ชันเสมือนในชนิดคลาสแบบไดนามิก

C # ไม่มีทางทำสิ่งนี้:

abstract class Foo {
    public void F() {
        Console.WriteLine(ToString()); // Always a virtual call!
    }

    public override string ToString() { System.Diagnostics.Debug.Assert(false); }
};

sealed class Bar : Foo {
    public override string ToString() { return "I'm called!"; }
}

VB, เช่น IL, สามารถออกการโทรที่ไม่เสมือนโดยใช้MyClass.Method()ไวยากรณ์ MyClass.ToString()ในข้างต้นนี้จะเป็น


9

ในการลอง / จับคุณสามารถป้อนบล็อกลองจากบล็อกการจับของตัวเองอีกครั้ง ดังนั้นคุณสามารถทำสิ่งนี้:

.try {
    // ...

  MidTry:
    // ...

    leave.s RestOfMethod
}
catch [mscorlib]System.Exception {
    leave.s MidTry  // branching back into try block!
}

RestOfMethod:
    // ...

AFAIK คุณไม่สามารถทำได้ใน C # หรือ VB


3
ฉันเห็นได้ว่าทำไมสิ่งนี้จึงถูกละเว้น - มีกลิ่นที่แตกต่างกันของGOTO
พื้นฐาน

3
ดูเหมือนว่าจะเกิดข้อผิดพลาดต่อไปใน VB.NET
Thomas Weller

1
สิ่งนี้สามารถทำได้จริงใน VB.NET คำสั่ง GoTo สามารถแยกสาขาจากCatchไปTryได้ เรียกใช้รหัสการทดสอบออนไลน์ที่นี่
mbomb007

9

ด้วย IL และ VB.NET คุณสามารถเพิ่มตัวกรองเมื่อตรวจพบข้อยกเว้น แต่ C # v3 ไม่รองรับคุณสมบัตินี้

ตัวอย่าง VB.NET นี้นำมาจากhttp://blogs.msdn.com/clrteam/archive/2009/02/05/catch-rethrow-and-filters-why-you-should-care.aspx (หมายเหตุWhen ShouldCatch(ex) = Trueใน จับข้อ):

Try
   Foo()
Catch ex As CustomBaseException When ShouldCatch(ex)
   Console.WriteLine("Caught exception!")
End Try

17
โปรดลบสิ่งที่= Trueทำให้ตาของฉันมีเลือดออก!
Konrad Rudolph

ทำไม? นี่คือ VB และไม่ใช่ C # ดังนั้นจึงไม่มีปัญหา = / == อยู่ ;-)
peSHIr

c # สามารถทำได้ "throw;" ดังนั้นผลลัพธ์เดียวกันสามารถทำได้
Frank Schwieterman

8
พ่อ, ฉันเชื่อว่าเขากำลังพูดถึง redudancy ของมัน
LegendLength

5
@ Frank Schwieterman: มีความแตกต่างระหว่างการจับและ rethrowing ข้อยกเว้นเมื่อเทียบกับการจับมัน ตัวกรองจะทำงานก่อนคำสั่ง "สุดท้าย" ที่ซ้อนกันดังนั้นสถานการณ์ที่ทำให้เกิดข้อยกเว้นจะยังคงมีอยู่เมื่อรันตัวกรอง ถ้ามีใครคาดว่าจะมีจำนวนมากที่จะถูกโยน SocketException ที่เงียบ ๆ อยากจะจับ แต่บางคนจะส่งสัญญาณปัญหาความสามารถในการตรวจสอบสถานะเมื่อมีปัญหาจะมีประโยชน์มาก
supercat


7

Native types
คุณสามารถทำงานกับประเภท int ดั้งเดิมและพื้นเมืองที่ไม่ได้ลงนามโดยตรง (ใน c # คุณสามารถทำงานกับ IntPtr เท่านั้นซึ่งไม่เหมือนกัน

Transient Pointers
คุณสามารถเล่นกับพอยน์เตอร์ชั่วคราวซึ่งเป็นพอยน์เตอร์สำหรับประเภทที่มีการจัดการ แต่รับประกันว่าจะไม่ย้ายในหน่วยความจำเนื่องจากไม่ได้อยู่ในฮีปที่ได้รับการจัดการ ไม่แน่ใจทั้งหมดว่าคุณจะใช้ประโยชน์ได้อย่างไรโดยไม่ยุ่งกับโค้ดที่ไม่มีการจัดการ แต่มันไม่ได้สัมผัสกับภาษาอื่นโดยตรงผ่านสิ่งต่างๆเช่น stackalloc

<Module>
คุณสามารถยุ่งเกี่ยวกับชั้นเรียนถ้าคุณต้องการ (คุณสามารถทำสิ่งนี้ได้โดยไม่ต้องใช้ IL)

.emitbyte

15.4.1.1 .emitbyte directive MethodBodyItem :: = … | .emitbyte Int32 คำสั่งนี้ทำให้ค่า 8 บิตที่ไม่ได้ลงนามถูกปล่อยโดยตรงไปยังสตรีม CIL ของวิธี ณ จุดที่คำสั่งปรากฏขึ้น [หมายเหตุ:. emitbyte directive ใช้สำหรับการสร้างการทดสอบ ไม่จำเป็นในการสร้างโปรแกรมปกติ จบบันทึก]

.entrypoint
คุณมีความยืดหยุ่นมากกว่านี้เล็กน้อยคุณสามารถนำไปใช้กับวิธีที่ไม่ได้เรียกว่า Main เป็นต้น

ได้อ่านสเป็คฉันแน่ใจว่าคุณจะพบอีกไม่กี่


+1 มีอัญมณีซ่อนอยู่ที่นี่ โปรดทราบว่า<Module>มีความหมายว่าเป็นคลาสพิเศษสำหรับภาษาที่ยอมรับวิธีการทั่วโลก (เช่น VB ทำ) แต่แท้จริงแล้ว C # ไม่สามารถเข้าถึงได้โดยตรง
Abel

ตัวชี้ชั่วคราวดูเหมือนว่าพวกมันจะมีประโยชน์มาก การคัดค้านหลายครั้งต่อโครงสร้างที่ไม่แน่นอนนั้นเกิดจากการละเลย ตัวอย่างเช่น "DictOfPoints (key) .X = 5;" จะสามารถใช้งานได้หาก DictOfPoints (คีย์) ส่งคืนตัวชี้ชั่วคราวไปยังโครงสร้างแทนที่จะคัดลอกโครงสร้างตามค่า
supercat

@supercat ที่ใช้ไม่ได้กับตัวชี้ชั่วคราวข้อมูลที่เป็นปัญหาอาจอยู่ในฮีป สิ่งที่คุณต้องการคือการอ้างอิงที่ส่งคืนเอริคพูดถึงที่นี่: blogs.msdn.com/b/ericlippert/archive/2011/06/23/…
ShuggyCoUk

@ShuggyCoUk: น่าสนใจ ฉันหวังว่า Eric จะสามารถโน้มน้าวใจให้ใช้วิธีการที่ "DictOfPoints (key) .X = 5;" สามารถทำงานได้ ในตอนนี้ถ้าใครอยากจะเขียนโค้ด DictOfPoints ให้ทำงานเฉพาะกับ Type Point (หรือประเภทอื่น ๆ ) โดยเฉพาะใคร ๆ ก็สามารถทำงานได้ แต่มันเป็นความเจ็บปวด BTW สิ่งหนึ่งที่ฉันต้องการจะดูจะเป็นวิธีที่หนึ่งสามารถเขียนฟังก์ชั่นทั่วไปปลายเปิดเช่น DoStuff <... > (someParams, ActionByRef <moreParams, ... >, ... ) ซึ่ง สามารถขยายได้ตามต้องการ ฉันเดาว่าจะมีวิธีการทำเช่นนั้นใน MSIL; กับบางความช่วยเหลือคอมไพเลอร์ ...
SuperCat

@ShuggyCoUk: ... จะเป็นอีกวิธีหนึ่งในการมีคุณสมบัติอ้างอิงโดยมีโบนัสเพิ่มเติมที่คุณสมบัติบางอย่างสามารถทำงานได้หลังจากทุกสิ่งที่บุคคลภายนอกจะทำกับการอ้างอิงเสร็จสิ้นแล้ว
supercat

6

คุณสามารถแฮ็ควิธีการแทนที่ co / contra-variance ซึ่ง C # ไม่อนุญาต (นี่ไม่เหมือนกับความแปรปรวนทั่วไป!) ฉันได้รับข้อมูลเพิ่มเติมเกี่ยวกับการนำไปใช้ที่นี่และส่วนที่1และ2


4

ฉันคิดว่าสิ่งที่ฉันต้องการ (ด้วยเหตุผลที่ผิดทั้งหมด) คือการสืบทอดใน Enums ดูเหมือนไม่ยากที่จะทำใน SMIL (เนื่องจาก Enums เป็นเพียงคลาส) แต่ไม่ใช่สิ่งที่ไวยากรณ์ C # ต้องการให้คุณทำ


4

นี่คือบางส่วนเพิ่มเติม:

  1. คุณสามารถมีวิธีการอินสแตนซ์พิเศษในผู้รับมอบสิทธิ์
  2. ผู้รับมอบสิทธิ์สามารถใช้อินเทอร์เฟซ
  3. คุณสามารถมีสมาชิกแบบสแตติกในผู้รับมอบสิทธิ์และอินเทอร์เฟซ

3

20) คุณสามารถปฏิบัติต่ออาร์เรย์ของไบต์เป็นอาร์เรย์ (เล็กกว่า 4x) ของ ints

ฉันใช้สิ่งนี้เมื่อเร็ว ๆ นี้เพื่อทำการติดตั้ง XOR ที่รวดเร็วเนื่องจากฟังก์ชัน CLR xor ทำงานกับ ints และฉันต้องการทำ XOR ในไบต์ของสตรีม

โค้ดผลลัพธ์ที่วัดได้จะเป็น 10 เท่าเร็วกว่าสิ่งที่เทียบเท่าใน C # (ทำ XOR ในแต่ละไบต์)

===

ฉันไม่มีถนนซ้อนทับ credz เพียงพอที่จะแก้ไขคำถามและเพิ่มสิ่งนี้ลงในรายการเป็น # 20 ถ้ามีคนอื่นที่อาจจะบวม ;-)


3
แทนที่จะจุ่มลงใน IL คุณสามารถทำสิ่งนี้ให้สำเร็จด้วยพอยน์เตอร์ที่ไม่ปลอดภัย ฉันคิดว่ามันคงเร็วและอาจเร็วกว่าเพราะจะไม่มีการตรวจสอบอย่าง จำกัด
P Daddy

3

มีผู้ใช้ obfuscators บางคนคุณสามารถมีฟิลด์ / วิธี / คุณสมบัติ / เหตุการณ์ทั้งหมดมีชื่อเหมือนกัน


1
ฉันวางตัวอย่างบนเว็บไซต์ของฉัน: jasonhaley.com/files/NameTestA.zip ในไฟล์ zip นั้นมี IL และ exe ที่มีคลาสพร้อมกับต่อไปนี้เหมือนกันทั้งหมด 'A': - ชื่อคลาสคือ A -Event ชื่อ A- วิธีการชื่อ A -Property ชื่อ A -2 Fields ชื่อ AI ไม่สามารถหาการอ้างอิงที่ดีที่จะชี้ให้คุณถึงแม้ว่าฉันอาจจะอ่านได้ทั้งใน ecma 335 spec หรือหนังสือของ Serge Lidin
เจสันเฮลีย์

2

Enum ไม่สามารถสืบทอดได้จริง:

คุณสามารถสืบทอดจากคลาส Enum แต่ผลลัพธ์จะไม่ทำงานเหมือน Enum โดยเฉพาะ มันจะทำงานไม่เหมือนประเภทค่า แต่เหมือนคลาสปกติ สิ่งที่เรียงลำดับคือ: IsEnum: True, IsValueType: True, IsClass: False

แต่นั่นไม่ใช่ประโยชน์โดยเฉพาะ (เว้นแต่คุณต้องการสร้างความสับสนให้กับบุคคลหรือรันไทม์เอง)


2

นอกจากนี้คุณยังสามารถรับคลาสจากผู้แทน System.Multicast ใน IL แต่คุณไม่สามารถทำได้ใน C #:

// คำจำกัดความของคลาสต่อไปนี้ผิดกฎหมาย:

คลาสสาธารณะ YourCustomDelegate: MulticastDelegate {}


1

นอกจากนี้คุณยังสามารถกำหนดวิธีการระดับโมดูล (aka ทั่วโลก) ใน IL และ C # ในทางตรงกันข้ามช่วยให้คุณสามารถกำหนดวิธีการตราบเท่าที่พวกเขาจะแนบมากับอย่างน้อยหนึ่งประเภท

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.