อะไรคือจุดประสงค์ของ hidebysig ในวิธี MSIL?


92

การใช้ ildasm และโปรแกรม C # เช่น

static void Main(string[] args)
{

}

ให้:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       2 (0x2)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ret
} // end of method Program::Main

โครงสร้างของ Hidebysig ทำอะไร?

คำตอบ:


156

จากECMA 335ส่วน 8.10.4 ของพาร์ติชัน 1:

CTS ให้การควบคุมอิสระสำหรับทั้งชื่อที่มองเห็นได้จากประเภทพื้นฐาน (การซ่อน) และการแบ่งปันสล็อตเค้าโครงในคลาสที่ได้รับ (การแทนที่) การซ่อนถูกควบคุมโดยการทำเครื่องหมายสมาชิกในคลาสที่ได้รับว่าซ่อนตามชื่อหรือซ่อนด้วยชื่อและลายเซ็น การซ่อนจะดำเนินการตามชนิดของสมาชิกเสมอนั่นคือชื่อฟิลด์ที่ได้รับสามารถซ่อนชื่อฟิลด์พื้นฐานได้ แต่ไม่ใช่ชื่อเมธอดชื่อคุณสมบัติหรือชื่อเหตุการณ์ ถ้าสมาชิกที่ได้รับถูกทำเครื่องหมายว่าซ่อนด้วยชื่อสมาชิกประเภทเดียวกันในคลาสพื้นฐานที่มีชื่อเดียวกันจะไม่ปรากฏในคลาสที่ได้รับ หากสมาชิกถูกทำเครื่องหมายซ่อนด้วยชื่อและลายเซ็นแสดงว่าเฉพาะสมาชิกประเภทเดียวกันที่มีชื่อและประเภทเดียวกัน (สำหรับฟิลด์) หรือลายเซ็นของเมธอด (สำหรับวิธีการ) เท่านั้นที่ถูกซ่อนจากคลาสที่ได้รับ การปรับใช้ความแตกต่างระหว่างรูปแบบการซ่อนทั้งสองรูปแบบนี้จัดทำโดยคอมไพเลอร์ภาษาต้นทางและไลบรารีการสะท้อน ไม่มีผลกระทบโดยตรงต่อ VES เอง

(ยังไม่ชัดเจนในทันทีจากนั้น แต่hidebysigหมายถึง "ซ่อนด้วยชื่อและลายเซ็น")

นอกจากนี้ในส่วนที่ 15.4.2.2 ของพาร์ติชัน 2:

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

ตัวอย่างเช่นสมมติว่าคุณมี:

public class Base
{
    public void Bar()
    {
    }
}

public class Derived : Base
{
    public void Bar(string x)
    {
    }
}

...

Derived d = new Derived();
d.Bar();

ถูกต้องเพราะBar(string) ไม่ได้ซ่อนBar()เนื่องจากคอมไพเลอร์ C # ใช้hidebysig. หากใช้ความหมาย "ซ่อนตามชื่อ" คุณจะไม่สามารถเรียกBar()ใช้การอ้างอิงประเภทได้Derivedเลยแม้ว่าคุณจะยังสามารถส่งไปยังฐานและเรียกแบบนั้นได้

แก้ไข: ฉันได้พยายามเพียงแค่นี้โดยการรวบรวมรหัสข้างต้นเพื่อ DLL ที่ ildasming มันลบhidebysigสำหรับBar()และBar(string), ilasming มันอีกครั้งแล้วพยายามที่จะเรียกBar()จากรหัสอื่น ๆ :

Derived d = new Derived();
d.Bar();

Test.cs(6,9): error CS1501: No overload for method 'Bar' takes '0' arguments

อย่างไรก็ตาม:

Base d = new Derived();
d.Bar();

(ไม่มีปัญหาในการคอมไพล์)


4
ในบทสรุปก็คือความแตกต่างระหว่างShadowsและOverloadsใน VB.NET
Mark Hurd

15

ตามคำตอบของ THE SKEET นอกจากนี้เหตุผลก็คือ Java และ C # อนุญาตให้ไคลเอนต์ของคลาสสามารถเรียกใช้เมธอดใด ๆ ที่มีชื่อเดียวกันรวมทั้งจากคลาสพื้นฐาน ในขณะที่ C ++ ไม่ได้: หากคลาสที่ได้รับกำหนดแม้แต่เมธอดเดียวที่มีชื่อเดียวกับเมธอดในคลาสฐานไคลเอ็นต์จะไม่สามารถเรียกเมธอดคลาสฐานได้โดยตรงแม้ว่าจะไม่ได้ใช้อาร์กิวเมนต์เดียวกันก็ตาม ดังนั้นคุณลักษณะนี้จึงรวมอยู่ใน CIL เพื่อรองรับทั้งสองวิธีในการโอเวอร์โหลด

ใน C ++ คุณสามารถนำเข้าชุดโอเวอร์โหลดที่มีชื่อหนึ่งชุดจากคลาสฐานได้อย่างมีประสิทธิภาพด้วยusingคำสั่งเพื่อให้พวกมันกลายเป็นส่วนหนึ่งของ "ชุดโอเวอร์โหลด" สำหรับชื่อเมธอดนั้น


1

อ้างอิงจากMicrosoft Docs

เมื่อสมาชิกในคลาสที่ได้รับถูกประกาศด้วยnewตัวปรับแต่งC # หรือตัวปรับแต่ง Visual Basic Shadowsสมาชิกสามารถซ่อนสมาชิกที่มีชื่อเดียวกันในคลาสพื้นฐานได้ C # ซ่อนสมาชิกคลาสพื้นฐานด้วยลายเซ็น นั่นคือถ้าสมาชิกคลาสพื้นฐานมีโอเวอร์โหลดหลายตัวคนเดียวที่ซ่อนอยู่คือคนที่มีลายเซ็นเหมือนกัน ในทางตรงกันข้าม Visual Basic จะซ่อนโอเวอร์โหลดคลาสพื้นฐานทั้งหมด ดังนั้นIsHideBySig จะส่งคืนfalseสมาชิกที่ประกาศด้วยShadows ตัวปรับแต่งVisual Basic และtrueบนสมาชิกที่ประกาศด้วยnewตัวปรับแต่งC #

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