95

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

4

3 回答 3

161

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()type 的引用Derived,尽管您仍然可以将其强制转换为 Base 并以这种方式调用它。

编辑:我刚刚尝试通过将上述代码编译为 DLL,对其进行 ildasming,删除hidebysigfor Bar()and 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();

(没有编译问题。)

于 2009-03-17T22:51:28.327 回答
15

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

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

于 2009-03-17T23:59:35.073 回答
2

根据微软文档

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

于 2018-03-27T15:41:12.020 回答