Какова цель 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?

rbrayb
источник

Ответы:

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, хотя вы все равно могли бы привести ее к Base и называть ее таким образом.

EDIT: Я просто попытался это путем составления вышеуказанного кода в 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.
Марк Херд
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 # .

Авестура
источник