Qual é o propósito de hidebysig em um método MSIL?

92

Usando ildasm e um programa C #, por exemplo

static void Main(string[] args)
{

}

dá:

.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

O que a construção hidebysig faz?

rbrayb
fonte

Respostas:

156

De ECMA 335 , seção 8.10.4 da partição 1:

O CTS fornece controle independente sobre os nomes que são visíveis a partir de um tipo base (ocultação) e o compartilhamento de slots de layout na classe derivada (substituição). O ocultamento é controlado marcando um membro na classe derivada como ocultar pelo nome ou ocultar pelo nome e assinatura. A ocultação é sempre realizada com base no tipo de membro, ou seja, nomes de campos derivados podem ocultar nomes de campos básicos, mas não nomes de métodos, nomes de propriedades ou nomes de eventos. Se um membro derivado for marcado como ocultar pelo nome, os membros do mesmo tipo na classe base com o mesmo nome não serão visíveis na classe derivada; se o membro estiver marcado como oculto por nome e assinatura, então apenas um membro do mesmo tipo com exatamente o mesmo nome e tipo (para campos) ou assinatura de método (para métodos) será oculto da classe derivada. A implementação da distinção entre essas duas formas de ocultação é fornecida inteiramente pelos compiladores da linguagem fonte e pela biblioteca de reflexão; não tem impacto direto no próprio VES.

(Não fica claro disso, mas hidebysigsignifica "ocultar pelo nome e assinatura".)

Também na seção 15.4.2.2 da partição 2:

hidebysig é fornecido para o uso de ferramentas e é ignorado pelo VES. Ele especifica que o método declarado oculta todos os métodos dos tipos de classe base que possuem uma assinatura de método correspondente; quando omitido, o método deve ocultar todos os métodos com o mesmo nome, independentemente da assinatura.

Por exemplo, suponha que você tenha:

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

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

...

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

Isso é válido, porque Bar(string) não esconde Bar(), porque o compilador C # usa hidebysig. Se ele usasse a semântica "ocultar pelo nome", você não seria capaz de chamar Bar()uma referência do tipo Derived, embora ainda pudesse lançá-la no Base e chamá-la dessa forma.

EDIT: Acabei de tentar compilar o código acima para uma DLL, ildasming-lo, removendo hidebysigfor Bar()e Bar(string), ilasming-lo novamente e, em seguida, tentar chamar Bar()de outro código:

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

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

Contudo:

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

(Sem problemas de compilação.)

Jon Skeet
fonte
4
Em resumo , é a diferença entre Shadowse Overloadsno VB.NET.
Mark Hurd
16

De acordo com a resposta de THE SKEET, além disso, a razão para isso é que Java e C # permitem que o cliente de uma classe chame quaisquer métodos com o mesmo nome, incluindo aqueles das classes base. Considerando que C ++ não: se a classe derivada define até mesmo um único método com o mesmo nome de um método na classe base, então o cliente não pode chamar diretamente o método da classe base, mesmo que não receba os mesmos argumentos. Portanto, o recurso foi incluído no CIL para oferecer suporte a ambas as abordagens de sobrecarga.

Em C ++, você pode importar efetivamente um conjunto nomeado de sobrecargas da classe base com uma usingdiretiva, para que se tornem parte do "conjunto de sobrecargas" para esse nome de método.

Daniel Earwicker
fonte
1

De acordo com o Microsoft Docs

Quando um membro em uma classe derivada é declarado com o newmodificador C # ou o Shadowsmodificador Visual Basic , ele pode ocultar um membro com o mesmo nome na classe base. C # oculta os membros da classe base por assinatura. Ou seja, se o membro da classe base tiver múltiplas sobrecargas, a única que ficará oculta é aquela que possui a assinatura idêntica. Em contraste, o Visual Basic oculta todas as sobrecargas da classe base. Portanto, IsHideBySig retorna falseem um membro declarado com o Shadows modificador Visual Basic e trueem um membro declarado com o newmodificador C # .

Avestura
fonte