Was ist der Zweck von hidebysig in einer MSIL-Methode?

92

Mit ildasm und einem C # -Programm, z

static void Main(string[] args)
{

}

gibt:

.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

Was macht das hidebysig-Konstrukt?

rbrayb
quelle

Antworten:

156

Aus ECMA 335 , Abschnitt 8.10.4 von Partition 1:

Das CTS bietet eine unabhängige Steuerung sowohl der Namen, die von einem Basistyp aus sichtbar sind (Ausblenden), als auch der Freigabe von Layout-Slots in der abgeleiteten Klasse (Überschreiben). Das Ausblenden wird gesteuert, indem ein Mitglied in der abgeleiteten Klasse entweder als nach Namen oder nach Name und Unterschrift ausgeblendet markiert wird. Das Ausblenden wird immer basierend auf der Art des Elements durchgeführt, dh abgeleitete Feldnamen können Basisfeldnamen ausblenden, jedoch keine Methodennamen, Eigenschaftsnamen oder Ereignisnamen. Wenn ein abgeleitetes Mitglied als nach Namen ausgeblendet markiert ist, sind Mitglieder derselben Art in der Basisklasse mit demselben Namen in der abgeleiteten Klasse nicht sichtbar. Wenn das Mitglied durch Name und Signatur als ausgeblendet markiert ist, wird nur ein Mitglied derselben Art mit genau demselben Namen und Typ (für Felder) oder Methodensignatur (für Methoden) vor der abgeleiteten Klasse ausgeblendet. Die Umsetzung der Unterscheidung zwischen diesen beiden Formen des Versteckens wird vollständig von den Compilern der Ausgangssprache und der Reflexionsbibliothek bereitgestellt. Es hat keine direkten Auswirkungen auf das VES selbst.

(Das ist nicht sofort klar, hidebysigbedeutet aber "durch Name und Unterschrift verstecken".)

Auch in Abschnitt 15.4.2.2 von Partition 2:

hidebysig wird für die Verwendung von Werkzeugen geliefert und vom VES ignoriert. Es gibt an, dass die deklarierte Methode alle Methoden der Basisklassentypen verbirgt, die eine übereinstimmende Methodensignatur haben. Wenn nicht angegeben, sollte die Methode alle gleichnamigen Methoden unabhängig von der Signatur ausblenden.

Angenommen, Sie haben als Beispiel:

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

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

...

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

Das ist gültig, weil Bar(string) es sich nicht versteckt Bar(), weil der C # -Compiler verwendet hidebysig. Wenn die Semantik "Nach Namen verstecken" verwendet würde , könnten Sie Bar()eine Referenz des Typs überhaupt nicht aufrufen Derived, obwohl Sie sie dennoch in Base umwandeln und so aufrufen könnten.

EDIT: Ich habe das gerade versucht , durch den obigen Code auf eine DLL kompilieren, ildasming es, das Entfernen hidebysigfür Bar()und Bar(string), ilasming es wieder, dann versuchen rufen Bar()von anderem Code:

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

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

Jedoch:

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

(Keine Kompilierungsprobleme.)

Jon Skeet
quelle
4
In Zusammenfassung , es ist der Unterschied zwischen Shadowsund Overloadsin VB.NET.
Mark Hurd
16

Gemäß der Antwort von THE SKEET ist der Grund dafür außerdem, dass Java und C # es dem Client einer Klasse ermöglichen, alle Methoden mit demselben Namen aufzurufen, einschließlich der Methoden aus Basisklassen. Während C ++ dies nicht tut: Wenn die abgeleitete Klasse auch nur eine einzelne Methode mit demselben Namen wie eine Methode in der Basisklasse definiert, kann der Client die Basisklassenmethode nicht direkt aufrufen, selbst wenn sie nicht dieselben Argumente akzeptiert. Daher wurde die Funktion in CIL aufgenommen, um beide Ansätze zur Überlastung zu unterstützen.

In C ++ können Sie effektiv einen benannten Satz von Überladungen aus der Basisklasse mit einer usingDirektive importieren , so dass sie Teil des "Überladungssatzes" für diesen Methodennamen werden.

Daniel Earwicker
quelle
1

Laut Microsoft Docs

Wenn ein Mitglied in einer abgeleiteten Klasse mit dem newModifikator C # oder dem Modifikator Visual Basic deklariert wird Shadows, kann es ein gleichnamiges Mitglied in der Basisklasse ausblenden. C # versteckt Basisklassenmitglieder durch Signatur. Das heißt, wenn das Basisklassenmitglied mehrere Überladungen aufweist, ist die einzige, die ausgeblendet ist, die mit der identischen Signatur. Im Gegensatz dazu verbirgt Visual Basic alle Überladungen der Basisklasse. So IsHideBySig kehrt falseerklärt auf einem Mitglied mit dem Visual Basic - Shadows Modifikator, und trueauf einem Mitglied mit dem C # erklärt newModifikator.

0xaryan
quelle