4

constコンパイル時に使用箇所がその値に置き換えられるのに、アセンブリにはまだ含まれているのはなぜですか? 少なくとも、これは IL DASM と Reflector が示すものです。

現在const、実行時のパフォーマンスに影響を与えずにコードを簡単に変更できるように、多くのマジック ナンバーと文字列を定義するために使用しています。

これで使用メモリには影響しないことがわかりましたが、携帯電話アプリなどで重要なコンパイル済みアセンブリのサイズには依然として影響します。

もう 1 つの欠点は、逆アセンブルされたコードを見ると、他の人がマジック ナンバーを理解しやすいことです。

コンパイラ (Mono と .NET) がこれを正確に行う理由に本当に興味がありますか?

4

2 に答える 2

6

この動作は、ECMA-335 標準(.NET と Mono の両方が実装されています) で指定されています。セクション II.22.9「定数」からの引用:

Constant情報はリフレクションを介して表示されますが、実行時の動作に直接影響しないことに注意してください (したがって、 によって提供されるような機能を実装するために使用できますSystem.Enum.ToString)。コンパイラは、コンパイル時にメタデータをインポートするときにこの情報を検査しますが、定数自体の値が使用されている場合は、コンパイラが出力する CIL ストリームに埋め込まれます。Constant実行時にテーブルにアクセスするための CIL 命令はありません。

つまり、const値は「インライン化」されますが (おそらくインライン化できるため、パフォーマンス上の理由から)、コンパイラやツールで検査できるようにメタデータに保持されます。

フィールドの -ness に対してメタデータが発行されなかった場合、const次のような結果になります (特に、これらは 2 つの例にすぎません)。

  • コンパイラーや Reflector などのツールは、通常のフィールドとフィールドを区別できなくなりましconstた。
  • を使用してフィールドを検査した場合、そのプロパティSystem.Reflectionは使用できなくなります。FieldInfo.IsLiteral
于 2013-04-06T09:53:49.060 に答える
2

アセンブリ サイズの増加は、基本的に、C# コンパイラがconst-ness に関する追加のメタデータを出力するためです。


この短いプログラムからどのような成果が期待できますか?

class Program
{
    public const int C = 0;
    public       int F = 0;

    static void Main(string[] args)
    {
        foreach (FieldInfo field in typeof(Program).GetFields())
        {
            Console.WriteLine("{0}: IsLiteral = {1}", field.Name, field.IsLiteral);
        }
    }
}

実際の出力は次のとおりです。

C: IsLiteral = True
F: IsLiteral = False

これは、C# ソースの宣言と正確に一致します。2 つのフィールド、そのうちの 1 つですconst

Constantここで、C# コンパイラがメタデータを出力しないことを決定したとしましょう。出力は次のようになります。

C: IsLiteral = False
F: IsLiteral = False

両方のフィールドが非として表示されるため、C# ソース コードと比較すると明らかに正しくありませんconst

最後に、C# コンパイラがメタデータをまったく出力しないことを決定したとしましょうC(とにかくフィールドの値を "インライン化" するため):

F: IsLiteral = False

リフレクションは、C# ソース コードに明確に存在するフィールドの存在を報告しなくなるため、これも正しくありません。少なくとも私にとっては、眉をひそめる良い機会になるでしょう。

これらの反例は、constフィールドに対しても完全なメタデータが発行されることがなぜ良いことなのかを明確にするはずです。

于 2013-04-06T10:58:43.523 に答える