MSIL方法中hidebysig的目的是什么?


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构造做什么?

Answers:


156

根据ECMA 335,分区1的8.10.4节:

CTS提供对从基本类型可见的名称(隐藏)和派生类中的布局插槽共享(覆盖)的独立控制。通过将派生类中的成员标记为按名称隐藏或按名称和签名隐藏来控制隐藏。隐藏总是基于成员的类型执行,也就是说,派生的字段名称可以隐藏基本字段名称,但不能隐藏方法名称,属性名称或事件名称。如果派生成员按名称标记为hide,则在基类中具有相同名称的同类成员在派生类中不可见;如果该成员按名称和签名标记为hide,则对派生类仅隐藏具有完全相同的名称和类型(对于字段)或方法签名(对于方法)的同类成员。这两种隐藏形式之间的区别的实现完全由源语言编译器和反射库提供;它对VES本身没有直接影响。

(目前尚不清楚,但是hidebysig意思是“按名称和签名隐藏”。)

同样在分区2的15.4.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()type的引用进行调用Derived,尽管您仍可以将其强制转换为Base并以这种方式进行调用。

编辑:我只是通过将以上代码编译为DLL来进行尝试,ildasming,删除hidebysigfor Bar()Bar(string),再次实现,然后尝试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。
马克·赫德2014年

16

根据THE SKEET的回答,此外,原因是Java和C#允许类的客户端调用具有相同名称的任何方法,包括来自基类的方法。而C ++却没有:如果派生类甚至定义了一个与基类中的方法同名的方法,那么客户端就不能直接调用基类方法,即使它没有采用相同的参数也是如此。因此,该功能已包含在CIL中,以支持两种重载方法。

在C ++中,您可以使用using指令从基类中有效地导入一组命名的重载,以使它们成为该方法名称的“重载集”的一部分。


1

根据Microsoft Docs

当使用C#new修饰符或Visual Basic Shadows修饰符声明派生类中的成员时,它可以在基类中隐藏相同名称的成员。C#通过签名隐藏基类成员。也就是说,如果基类成员具有多个重载,则唯一隐藏的重载是具有相同签名的重载。相比之下,Visual Basic隐藏所有基类重载。因此,IsHideBySig 返回false使用Visual Basic Shadows 修饰符true声明的成员和使用C#new修饰符声明的成员。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.