web-dev-qa-db-ja.com

MSILメソッドでのhidebysigの目的は何ですか?

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コンストラクトは何をしますか?

88
nzpcmad

ECMA 335 から、パーティション1のセクション8.10.4:

CTSは、基本タイプから見える名前(非表示)と派生クラスのレイアウトスロットの共有(上書き)の両方を独立して制御します。非表示は、派生クラスのメンバーを名前で非表示にするか、名前と署名で非表示にするかのいずれかとしてマークすることによって制御されます。非表示は常にメンバーの種類に基づいて実行されます。つまり、派生フィールド名はベースフィールド名を非表示にできますが、メソッド名、プロパティ名、イベント名は非表示にできません。派生メンバーが名前で非表示とマークされている場合、同じ名前の基本クラスの同じ種類のメンバーは、派生クラスでは表示されません。メンバーが名前と署名によって非表示とマークされている場合、完全に同じ名前とタイプ(フィールドの場合)またはメソッドシグネチャ(メソッドの場合)を持つ同じ種類のメンバーのみが派生クラスから非表示になります。これら2つの形式の非表示の区別の実装は、ソース言語コンパイラとリフレクションライブラリによって完全に提供されます。 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();

C#コンパイラはhidebysigを使用するため、Bar(string)Bar()を非表示にしないため、これは有効です。 「名前で隠す」セマンティクスを使用する場合、タイプDerivedの参照でBar()を呼び出すことはできませんが、Baseにキャストしてそれを呼び出すことはできます。仕方。

編集:上記のコードをDLLにコンパイルし、それをildasmingし、Bar()Bar(string)hidebysigを削除し、もう一度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();

(コンパイルの問題はありません。)

152
Jon Skeet

THE SKEETの回答によると、これの理由はさらにJavaおよびC#により、クラスのクライアントが基本クラスのメソッドを含む同じ名前のメソッドを呼び出すことができるようになることです。C++ではnot:派生クラスで基本クラスのメソッドと同じ名前のメソッドが1つでも定義されている場合、同じ引数を取らなくても、クライアントは基本クラスメソッドを直接呼び出すことはできません。 CILでは、オーバーロードへの両方のアプローチをサポートします。

C++では、usingディレクティブを使用して、基本クラスからオーバーロードの1つの名前付きセットを効果的にインポートして、それらがそのメソッド名の「オーバーロードセット」の一部になるようにすることができます。

15

Microsoft Docs によると

派生クラスのメンバーがC#のnew修飾子またはVisual BasicのShadows修飾子を使用して宣言されている場合、基本クラスの同じ名前のメンバーを非表示にすることができます。 C#は基本クラスのメンバーをシグネチャで非表示にします。つまり、基本クラスのメンバーに複数のオーバーロードがある場合、非表示になるのは、同じシグネチャを持つオーバーロードだけです。対照的に、Visual Basicはすべての基本クラスのオーバーロードを非表示にします。したがって、 IsHideBySig は、Visual Basicのfalse修飾子で宣言されたメンバーではShadowsを返し、C#のtrue修飾子で宣言されたメンバーではnewを返します。

1
0xaryan