Qual é o propósito de hidebysig em um método MSIL?
-
19-08-2019 - |
Pergunta
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 significa a construção hidebysig fazer?
Solução
A partir ECMA 335 , secção 8.10.4 da partição 1:
O CTS fornece controle independente sobre ambos os nomes que são visíveis a partir de um tipo de base (de cobertura) e o compartilhamento de espaços de layout no derivado classe (substituir). esconderijo é controlada por marcação de um membro na classe derivada quer como ocultar pelo nome ou esconder por nome e assinatura. Se escondendo é sempre realizada com base no tipo do membro, isto é, derivado campo nomes podem esconder nomes de campos base, mas não nomes de métodos, nomes de propriedades, ou nomes de eventos. Se um membro é derivado hide marcado por nome, membros depois de do mesmo tipo na classe base com o mesmo nome não são visíveis no classe derivada; se o membro é marcada hide pelo nome e assinatura, em seguida, apenas uma membro da mesma espécie com exatamente o mesmo nome e tipo (por campos) ou método de assinatura (por métodos) é escondido da classe derivada. Implementação da distinção entre estas duas formas de esconde inteiramente efectuados por idioma de origem compiladores e a biblioteca reflexão; não tem impacto direto sobre as VES em si.
(Não é imediatamente claro disso, mas meios hidebysig
"esconder por 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. isto Especifica que o método declarado couros Todos os métodos da base de classe tipos que têm um método de correspondência assinatura; quando omitida, o método deve esconder todos os métodos do mesmo nome, independentemente da assinatura.
Como um exemplo, suponha que você tem:
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 hide Bar()
, porque o compilador C # usa hidebysig
. Se usado "esconder pelo nome" semântica, você não seria capaz de chamar Bar()
em tudo em uma referência do tipo Derived
, embora você ainda pode lançá-lo para a Base e chamá-lo dessa forma.
EDIT: Eu apenas tentei isso por compilar o código acima para uma DLL, ildasming-lo, removendo hidebysig
para Bar()
e Bar(string)
, ilasming-lo novamente, em seguida, tentar Bar()
telefonema de outro código:
Derived d = new Derived();
d.Bar();
Test.cs(6,9): error CS1501: No overload for method 'Bar' takes '0' arguments
No entanto:
Base d = new Derived();
d.Bar();
(Sem problemas de compilação.)
Outras dicas
De acordo com a resposta do SKEET, além disso, a razão para isso é que Java e C # permitir que o cliente de uma classe para chamar quaisquer métodos com o mesmo nome, incluindo os de classes base. Considerando C ++ não faz: se os define classe derivada 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 ele não leva os mesmos argumentos. Assim, o recurso foi incluído no CIL para suportar ambas as abordagens a uma sobrecarga.
Em C ++ você pode efetivamente importar um conjunto nomeado de sobrecargas da classe base com uma directiva using
, para que se tornem parte do "set sobrecarga" para esse nome método.
De acordo com o Microsoft Docs
Quando um membro em uma classe derivada é declarada com o modificador C #
new
ou o modificadorShadows
Visual Basic, ele pode esconder um membro da mesma nome na classe base. C # peles dos alunos de base por assinatura. Este é, se o membro da classe base tem várias sobrecargas, o único que está escondido é a que tem a assinatura idêntica. Por contraste, Visual Basic oculta todas as sobrecargas de classe base. Assim, IsHideBySig retornosfalse
em um membro declarado com oShadows
Visual Basic modificador, etrue
em um membro declarado com o modificador C #new
.