2009-09-09 5 views
11

Tをクラスに制約するジェネリックメソッドがMSILコードを生成するのにボクシングの指示を持つ理由は誰にでも分かりますか?T:classのconstaintを持つジェネリックメソッドはなぜボクシングになりますか?

Tが参照型に制約されているので、生成されたコードはボクシングを行う必要がないので、私はこれに非常に驚いていました。ここで

protected void SetRefProperty<T>(ref T propertyBackingField, T newValue) where T : class 
{ 
    bool isDifferent = false; 

    // for reference types, we use a simple reference equality check to determine 
    // whether the values are 'equal'. We do not use an equality comparer as these are often 
    // unreliable indicators of equality, AND because value equivalence does NOT indicate 
    // that we should share a reference type since it may be a mutable. 

    if (propertyBackingField != newValue) 
    { 
     isDifferent = true; 
    } 
} 

生成ILです:

.method family hidebysig instance void SetRefProperty<class T>(!!T& propertyBackingField, !!T newValue) cil managed 
{ 
    .maxstack 2 
    .locals init (
     [0] bool isDifferent, 
     [1] bool CS$4$0000) 
    L_0000: nop 
    L_0001: ldc.i4.0 
    L_0002: stloc.0 
    L_0003: ldarg.1 
    L_0004: ldobj !!T 
    L_0009: box !!T 
    L_000e: ldarg.2 
    L_000f: box !!T 
    L_0014: ceq 
    L_0016: stloc.1 
    L_0017: ldloc.1 
    L_0018: brtrue.s L_001e 
    L_001a: nop 
    L_001b: ldc.i4.1 
    L_001c: stloc.0 
    L_001d: nop 
    L_001e: ret 
} 

お知らせボックス!! T指示ここ

は、C#のコードです。

これがなぜ生成されているのですか?

これを回避する方法はありますか?

おかげで、 フィル

+1

Jonが出ています:-) – Peter

+7

私はあなたの答えを見つけました。それは重複しています!偉大な質問、方法によって:) http://stackoverflow.com/questions/646517/boxing-when-using-generics-in-cを参照してください –

+3

私がリンクしている答えの要点は、参照のボクシングの指示タイプは効果的にノップです。これにより、コンパイラはジェネリック型引数として参照型を使用して作成された閉じられた構築型に対して、JITによって削除できるボクシング命令を自由に発行できます。あなたの場合( 'T'は参照型として制約されているので)、放出された2つのボクシング命令のどちらも実行されません。 –

答えて

2

box命令のパフォーマンス低下を心配する必要はありません。なぜなら、その引数が参照型の場合、box命令は何もしないからです。 box命令が作成されたことさえ(奇妙な/より簡単なコード生成時の設計ですか?)ということはまだ奇妙です。

0

私はこれは、設計者が意図していると信じています。あなたはTを特定のクラスに束縛していないので、それをオブジェクトにキャストする可能性が最も高いです。したがって、あなたはなぜILを見るボクシングを参照してください。 ActualClass

+3

T:ActualClassを実行する場合、なぜジェネリックスに気をつけますか? –

+0

あなたはTをより高いレベルに制限することができるので... iSomeInterfaceのように... –

+1

クリスは、Tがオブジェクトであれば、スタックを押す前にすでにボックス化されていませんか?それでは、なぜボクシング作業を行う必要がありますか? Tがオブジェクトである場合、==演算子が参照等価をチェックすることを期待します。したがって、これはun/boxing操作を必要としません。 – Phil

1

私はボクシングがocurringされている理由はわからない:

私はTがどこでこのコードをしようとするだろう。ボクシングを避けるための1つの方法は、それを使用しないことです。ボクシングなしで再コンパイルするだけです。例:

.assembly recomp_srp 
{ 
    .ver 1:0:0:0 
} 

.class public auto ansi FixedPBF 
{ 

.method public instance void .ctor() cil managed 
{ 

} 

.method hidebysig public instance void SetRefProperty<class T>(!!T& propertyBackingField, !!T newValue) cil managed 
{ 
    .maxstack 2  
     .locals init (bool isDifferent, bool CS$4$0000) 

     ldc.i4.0 
     stloc.0 
     ldarg.1 
     ldobj !!T 
     ldarg.2 
     ceq 
     stloc.1 
     ldloc.1 
     brtrue.s L_0001 
     ldc.i4.1 
     stloc.0 
     L_0001: ret 

} 

} 

...あなたは、単にのような再コンパイルすることができますrecomp_srp.msilファイルに保存する場合:

ILDASM/DLLのrecomp_srp.msil

そして、それは上のボクシングなしでOK走ります私の最後:

 FixedPBF TestFixedPBF = new FixedPBF(); 

     TestFixedPBF.SetRefProperty<string>(ref TestField, "test2"); 

は...もちろん、私は国民に保護されたから、あなたは再び変更を加える必要があると実装の残りの部分を提供することを変更しました。

関連する問題