31

数日前、オーバーフローに関するこの質問への回答を書いているときに、C# コンパイラが期待どおりの動作をしていないことに少し驚きました。コード スニペットについては、次を参照してください。

初め:

object[] array = new object[1];

for (int i = 0; i < 100000; i++)
{
    ICollection<object> col = (ICollection<object>)array;
    col.Contains(null);
}

2番:

object[] array = new object[1];

for (int i = 0; i < 100000; i++)
{
    ICollection<object> col = array;
    col.Contains(null);
}

2 つのスニペットのコードの唯一の違いは、へのキャストICollection<object>です。object[]はインターフェイスを明示的に実装しているためICollection<object>、2 つのスニペットが同じ IL にコンパイルされ、したがって同一になると予想していました。しかし、それらでパフォーマンス テストを実行すると、後者が前者の約 6 倍高速であることがわかりました。

castclass両方のスニペットの IL を比較した後、最初のスニペットの IL 命令を除いて、両方のメソッドが同一であることに気付きました。

これに驚いて、なぜ C# コンパイラがここで「スマート」でないのか疑問に思います。物事は見かけほど単純ではないのに、なぜ C# コンパイラはここで少しナイーブなのでしょうか?

4

3 に答える 3

4

これは大まかな推測ですが、配列とその汎用 IEnumerable との関係についてだと思います。

.NET Framework バージョン 2.0 では、Array クラスは System.Collections.Generic.IList、System.Collections.Generic.ICollection、および System.Collections.Generic.IEnumerable ジェネリック インターフェイスを実装します。実装は実行時に配列に提供されるため、ドキュメント ビルド ツールには表示されません。その結果、ジェネリック インターフェイスは Array クラスの宣言構文に表示されず、配列をジェネリック インターフェイス型にキャストすることによってのみアクセスできるインターフェイス メンバー (明示的なインターフェイスの実装) に関するリファレンス トピックはありません。これらのインターフェイスのいずれかに配列をキャストするときに注意すべき重要な点は、要素を追加、挿入、または削除するメンバーが NotSupportedException をスローすることです。

MSDN の記事を参照してください。

これが .NET 2.0+ に関連しているかどうかは明らかではありませんが、この特殊なケースでは、実行時にのみ有効になる場合にコンパイラが式を最適化できない理由は完全に理にかなっています。

于 2010-02-07T12:56:08.330 に答える
2

これは、コンパイラでキャストを抑制する機会を逃しただけではないようです。次のように書くとうまくいきます。

    ICollection<object> col = array as ICollection<object>;

これは、キャストが例外をスローする可能性があるため、保守的になりすぎることを示唆しています。ただし、非ジェネリック ICollection にキャストすると機能します。彼らは単にそれを見落としていたと結論付けます。

ここには、より大きな最適化の問題があります。JIT コンパイラーは、ループ不変ホイスト最適化を適用しません。次のようにコードを書き直したはずです。

object[] array = new object[1];
ICollection<object> col = (ICollection<object>)array;
for (int i = 0; i < 100000; i++)
{
    col.Contains(null);
}

たとえば、これは C/C++ コード ジェネレーターの標準的な最適化です。それでも、JIT オプティマイザーは、そのような最適化の可能性を発見するために必要な種類の分析に多くのサイクルを費やすことはできません。これに関する幸いなことに、最適化されたマネージ コードは依然としてデバッグ可能です。そして、パフォーマンスの高いコードを書く C# プログラマーの役割はまだあるということです。

于 2010-02-07T15:50:18.600 に答える