Jaki jest cel hidebysig w metodzie MSIL?

92

Korzystanie z ildasm i programu C # np

static void Main(string[] args)
{

}

daje:

.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

Co robi konstrukcja hidebysig?

rbrayb
źródło

Odpowiedzi:

156

Od ECMA 335 , sekcja 8.10.4 partycji 1:

CTS zapewnia niezależną kontrolę zarówno nad nazwami, które są widoczne z typu podstawowego (ukrywanie), jak i współdzieleniem szczelin układu w klasie pochodnej (nadpisywanie). Ukrywanie jest kontrolowane przez oznaczenie elementu członkowskiego w klasie pochodnej jako ukrycia według nazwy lub ukrycia według nazwy i podpisu. Ukrywanie jest zawsze wykonywane na podstawie rodzaju elementu członkowskiego, co oznacza, że ​​nazwy pól pochodnych mogą ukrywać nazwy pól bazowych, ale nie nazwy metod, nazwy właściwości lub nazwy zdarzeń. Jeśli element członkowski pochodny jest oznaczony jako ukryj według nazwy, elementy członkowskie tego samego rodzaju w klasie bazowej o tej samej nazwie nie są widoczne w klasie pochodnej; jeśli element członkowski jest oznaczony jako ukryj według nazwy i podpisu, wówczas tylko element członkowski tego samego rodzaju o dokładnie tej samej nazwie i typie (dla pól) lub sygnaturze metody (dla metod) jest ukryty w klasie pochodnej. Implementacja rozróżnienia między tymi dwoma formami ukrywania jest całkowicie zapewniana przez kompilatory języka źródłowego i bibliotekę refleksji; nie ma bezpośredniego wpływu na sam VES.

(Nie jest to od razu jasne, ale hidebysigoznacza „ukryj według nazwy i podpisu”).

Również w sekcji 15.4.2.2 przegrody 2:

hidebysig jest dostarczany do użytku z narzędziami i jest ignorowany przez VES. Określa, że ​​zadeklarowana metoda ukrywa wszystkie metody typów klas bazowych, które mają pasującą sygnaturę metody; jeśli zostanie pominięty, metoda powinna ukryć wszystkie metody o tej samej nazwie, niezależnie od podpisu.

Na przykład załóżmy, że masz:

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

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

...

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

To jest poprawne, ponieważ Bar(string) się nie ukrywa Bar(), ponieważ kompilator C # używa hidebysig. Gdyby używał semantyki „ukryj według nazwy”, nie byłbyś w stanie Bar()w ogóle wywołać referencji typu Derived, chociaż nadal możesz rzutować je na Base i nazwać w ten sposób.

EDIT: Właśnie próbowałem kompilując powyższy kod do pliku DLL, ildasming go, usuwając hidebysigna Bar()i Bar(string), ilasming go ponownie, a następnie próby wywołania Bar()z innego kodu:

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

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

Jednak:

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

(Brak problemów z kompilacją).

Jon Skeet
źródło
4
W skrócie , jest to różnica pomiędzy Shadowsi Overloadsw VB.NET.
Mark Hurd
15

Zgodnie z odpowiedzią THE SKEET, dodatkowo jest to spowodowane tym, że Java i C # pozwalają klientowi klasy na wywoływanie dowolnych metod o tej samej nazwie, w tym z klas bazowych. Podczas gdy C ++ nie: jeśli klasa pochodna definiuje nawet jedną metodę o takiej samej nazwie jak metoda w klasie bazowej, to klient nie może bezpośrednio wywołać metody klasy bazowej, nawet jeśli nie przyjmuje ona tych samych argumentów. Tak więc funkcja została uwzględniona w CIL, aby obsługiwać oba podejścia do przeciążania.

W C ++ można efektywnie zaimportować jeden nazwany zestaw przeciążeń z klasy bazowej za pomocą usingdyrektywy, aby stały się one częścią „zestawu przeciążeń” dla tej nazwy metody.

Daniel Earwicker
źródło
1

Według Microsoft Docs

Gdy element członkowski w klasie pochodnej jest zadeklarowany przy użyciu newmodyfikatora C # lub modyfikatora Visual Basic Shadows, może ukryć element członkowski o tej samej nazwie w klasie bazowej. C # ukrywa członków klasy bazowej według podpisu. Oznacza to, że jeśli element członkowski klasy bazowej ma wiele przeciążeń, jedyną ukrytą jest ta, która ma identyczny podpis. Z kolei Visual Basic ukrywa wszystkie przeciążenia klasy bazowej. W związku z tym IsHideBySig zwraca falseelement członkowski zadeklarowany za pomocą Shadows modyfikatora Visual Basic i trueelement członkowski zadeklarowany za pomocą newmodyfikatora C # .

Avestura
źródło