MSIL 方法中 hidebysig 的用途是什么?

发布于 2024-07-16 04:37:29 字数 352 浏览 8 评论 0原文

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

Using ildasm and a C# program e.g.

static void Main(string[] args)
{

}

gives:

.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

What does the hidebysig construct do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

黑白记忆 2024-07-23 04:37:29

来自 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。 如果它使用“按名称隐藏”语义,则您根本无法对 Derived 类型的引用调用 Bar(),尽管您仍然可以对其进行强制转换到基地并这样称呼它。

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

没有编译问题。)

From ECMA 335, section 8.10.4 of partition 1:

The CTS provides independent control
over both the names that are visible
from a base type (hiding) and the
sharing of layout slots in the derived
class (overriding). Hiding is
controlled by marking a member in the
derived class as either hide by name
or hide by name-and-signature. Hiding
is always performed based on the kind
of member, that is, derived field
names can hide base field names, but
not method names, property names, or
event names. If a derived member is
marked hide by name, then members of
the same kind in the base class with
the same name are not visible in the
derived class; if the member is marked
hide by name-and-signature then only a
member of the same kind with exactly
the same name and type (for fields) or
method signature (for methods) is
hidden from the derived class.
Implementation of the distinction
between these two forms of hiding is
provided entirely by source language
compilers and the reflection library;
it has no direct impact on the VES
itself.

(It's not immediately clear from that, but hidebysig means "hide by name-and-signature".)

Also in section 15.4.2.2 of partition 2:

hidebysig is supplied for the use of
tools and is ignored by the VES. It
specifies that the declared method
hides all methods of the base class
types that have a matching method
signature; when omitted, the method
should hide all methods of the same
name, regardless of the signature.

As an example, suppose you have:

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

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

...

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

That's valid, because Bar(string) doesn't hide Bar(), because the C# compiler uses hidebysig. If it used "hide by name" semantics, you wouldn't be able to call Bar() at all on a reference of type Derived, although you could still cast it to Base and call it that way.

EDIT: I've just tried this by compiling the above code to a DLL, ildasming it, removing hidebysig for Bar() and Bar(string), ilasming it again, then trying to call Bar() from other code:

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

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

However:

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

(No compilation problems.)

红尘作伴 2024-07-23 04:37:29

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

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

As per THE SKEET's answer, in addition the reason for this is that Java and C# allow the client of a class to call any methods with the same name, including those from base classes. Whereas C++ does not: if the derived class defines even a single method with the same name as a method in the base class, then the client cannot directly call the base class method, even if it doesn't take the same arguments. So the feature was included in CIL to support both approaches to overloading.

In C++ you can effectively import one named set of overloads from the base class with a using directive, so that they become part of the "overload set" for that method name.

依 靠 2024-07-23 04:37:29

根据微软文档

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

According to Microsoft Docs

When a member in a derived class is declared with the C# new modifier
or the Visual Basic Shadows modifier, it can hide a member of the same
name in the base class. C# hides base class members by signature. That
is, if the base class member has multiple overloads, the only one that
is hidden is the one that has the identical signature. By contrast,
Visual Basic hides all the base class overloads. Thus, IsHideBySig
returns false on a member declared with the Visual Basic Shadows
modifier, and true on a member declared with the C# new modifier.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文