9

C#4.0の「オプションのパラメーター」機能は非常に興味深いものであることがわかったので、それらがどのように実現したかを理解しようとしました。だから私はこのようなメソッドを書きました:

private static void A(int a = 5) { }

コンパイルしてからILDASMで逆コンパイルします。これは、ILコードです。

.method private hidebysig static void  A([opt] int32 a) cil managed
{
  .param [1] = int32(0x00000005)
  // Code size       2 (0x2)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ret
} // end of method Program::A

そして、メタデータにこれが含まれています。

(1)ParamToken:(08000002)名前:フラグ:[オプション] [HasDefault](00001010)デフォルト:(I4)5

そこで私は手がかりに従い、次のようなメソッドを作成しました。

private static void B([Optional, DefaultParameterValue(78)]int b) { }

それをコンパイルして逆コンパイルしたところ、C#コンパイラーがメソッドAとB(名前を除く)に対してほぼ同じMSILコードを生成していることがわかりました。

ご覧のとおり、ILコードには属性の兆候がなく、間違っていると感じたため、次のようなカスタム属性を作成しました。

[AttributeUsage(AttributeTargets.Parameter)]
public class MyTestAttribute : Attribute
{
}

次に、次のようにメソッドCで使用しました。

private static void C([MyTest]int c) { }

それをコンパイルしてから逆コンパイルしました、そしてハァッ、私はこれを見つけました:

.method private hidebysig static void  C(int32 c) cil managed
{
  .param [1]
  .custom instance void ConsoleApplication1.MyTestAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       2 (0x2)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ret
} // end of method Program::C

メソッド本体の2行目は、カスタム属性のctorを呼び出します。

だからこれは私の疑問につながります:

  1. [opt]はどういう意味ですか?メソッドAとBのパラメータの前に表示されるものを意味します。
  2. メソッドCがそのパラメーターに適用される属性のコンストラクターを呼び出すのに、メソッドAとBは呼び出さないのはなぜですか?
  3. メタデータにDefaultParameterValueAttributeの兆候が見つからないようですが、OptionalAttributeとMyTestAttributeは見つかります。何故ですか?足りないものはありますか?

前もって感謝します。

4

2 に答える 2

10

FlagsParamメタデータテーブルは列を介してオプション値とデフォルト値を既に記述できるため、C#コンパイラは属性を出力する必要はありません。

ECMA 335の23.1.13から:

Flag            Value   Description
-----------------------------------------------------
In              0x0001  Parameter is [In]  
Out             0x0002  Parameter is [Out]  
Optional        0x0010  Parameter is optional  
HasDefault      0x1000  Parameter has a default value  
HasFieldMarshal 0x2000  Parameter has FieldMarshal  

パラメータには、オプションであり、デフォルト値(0x0010 | 0x1000)を持つことを指定するフラグ値を含めることができます。デフォルト値を持つパラメーターには、Constantメタデータテーブルに関連付けられたトークンがあります。

Constantメタデータテーブルには、Parent問題のParamトークンとなるValue列と、デフォルト値が格納されているblobヒープへのインデックスとなる列があります。

だからあなたの質問に答えるために:

  1. [opt]はFlags、Paramトークンの列にオプションのフラグが設定されていることを意味します。
  2. 上で述べたように、ここでの私の推測では、C#コンパイラはOptional / DefaultParameterValue属性を認識し、それらをパラメータフラグに変換しているだけです。
  3. 編集:パラメーターにオプションフラグが使用されているにもかかわらず、C#コンパイラがOptionalAttributeの未使用のTypeRefを発行しているようです。ただし、DefaultParameterValueAttributeのTypeRefは発行されません。未使用のTypeRefs/MemberRefsを発行するための小さなコンパイラバグである可能性があります。
于 2011-03-31T09:24:11.337 に答える
2

2/3; コンパイラがILメタデータとして解釈する属性はいくつかありますが、実際には属性ではありません。これがここに当てはまるようです。[Serializable]別の例です。デフォルトのデータは次のとおりですDefault: (I4) 5。-コード内のすべての属性がメタデータ内の属性になるわけではありません(ここでも、ここで確認してい[Serializable]ます)


その点について[Serializable](コメント); 次に例を示します。

[Description("abc")]
class Foo { }

[Serializable]
class Bar { }

コアILは次のとおりです。

.class private auto ansi beforefieldinit Foo
    extends [mscorlib]System.Object
{
    .custom instance void [System]System.ComponentModel.DescriptionAttribute::.ctor(string) = { string('abc') }
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
    }

}
.class private auto ansi serializable beforefieldinit Bar
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
    }

}

Foo任意の属性の場合)では、次のようになります。

.custom instance void [System]System.ComponentModel.DescriptionAttribute::.ctor(string) = { string('abc') }

ただし、これは適用されません[Serializable]。代わりに、それはタイプの一部です:

.class private auto ansi serializable beforefieldinit Bar
于 2011-03-31T09:24:28.343 に答える