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

时间:2009-03-17 22:47:28

标签: cil

使用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构造有什么作用?

3 个答案:

答案 0 :(得分:148)

来自ECMA 335,分区1的第8.10.4节:

  

CTS提供独立控制   在两个可见的名称上   从基类型(隐藏)和   在派生中共享布局槽   上课(重写)。隐藏是   通过标记成员来控制   派生类可以按名称隐藏   或通过名称和签名隐藏。藏   总是根据种类进行   成员,即派生字段   名称可以隐藏基本字段名称,但是   不是方法名,属性名或   事件名称。如果派生成员是   按名称标记隐藏,然后是成员   与基类中的同类   在...中看不到相同的名字   派生类;如果成员被标记   隐藏名称和签名然后只有一个   完全相同的成员   相同的名称和类型(对于字段)或   方法签名(方法)是   隐藏在派生类中。   执行区别   这两种隐藏形式之间是   完全由源语言提供   编译器和反射库;   它对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()类型的引用上调用Derived,尽管您仍然可以将其强制转换为Base并以此方式调用它。

编辑:我刚尝试将上面的代码编译成DLL,ildasming,删除hidebysigBar()的{​​{1}},再次将其重新填充,然后尝试调用来自其他代码的Bar(string)

Bar()

然而:

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

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

(没有编译问题。)

答案 1 :(得分:14)

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

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

答案 2 :(得分:0)

根据Microsoft Docs

  

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