C# コンパイラーがコードを誤って最適化する
-
02-07-2019 - |
質問
リモート Web サーバー上で ASP.NET アプリケーションを実行していますが、次のエラーが発生し始めました。
Method not found: 'Void System.Collections.Generic.ICollection`1..ctor()'.
DLL 内のコードを逆アセンブルしましたが、コンパイラーがコードを誤って最適化しているようです。(Set は一意のオブジェクトのセットを実装するクラスであることに注意してください。これは IEnumerable から継承します。) この行:
Set<int> set = new Set<int>();
次の行にコンパイルされます。
Set<int> set = (Set<int>) new ICollection<CalendarModule>();
CalendarModule クラスはまったく関係のないクラスです。.NET がこのようなコードを誤ってコンパイルしていることに気付いた人はいるでしょうか?
アップデート #1: この問題は Microsoft によってもたらされたものと思われます。 ILMerge 道具。現在、それを克服する方法を検討中です。
アップデート #2: これまでのところ、この問題を解決する 2 つの方法が見つかりました。根本的な問題が何なのかはよくわかりませんが、次の両方で問題は解決します。
最適化をオフにします。
別のマシン上の ILMerge を使用してアセンブリをマージします。
そのため、ビルド マシンの構成が何らかの形で間違っているのではないか (リリースのビルドにマシンを 1 年以上使用していることを考えると、これは奇妙です)、それとも何か他の問題があるのではないかと疑問が残ります。
解決
ああ、ILMerge さん、質問にあるその追加情報は問題の解決に本当に役に立ちます。.net コンパイラがこのような形で失敗するとは思いませんでしたが、ILMerge では (その動作を考えると) この種の現象が時々発生することは予想されます。
私の推測では、2 つのアセンブリが同じ最適化「トリック」を使用しており、マージされると競合が発生すると考えられます。
Microsoft にバグを報告しましたか?
当面の回避策は、ソースからアセンブリを 1 つのアセンブリとして再コンパイルし、ILMerge の必要性を回避することです。csproj ファイルは単なる XML リストであるため、基本的にマージが簡単で、追加の MSBuild ステップとして自動化できます。
他のヒント
あなたが見ているアセンブリが実際に問題のソース コードから生成されたものであると確信していますか?小さなテストケースでこの問題を再現できますか?
編集: Reflector を使用している場合、MSIL から C# への変換が正しくない可能性があります -- Reflector は逆コンパイル時に常に 100% 正確であるとは限りません。MSIL はどのようなものですか?
編集2: ふーむ...Reflector に問題があるわけではないことに今気づきました。そうでなければ、実行時にそのエラー メッセージが表示されることはなかったはずです。
これは、.Net コンパイルの問題よりもリフレクション ツールの問題である可能性が高くなります。発生しているエラー - リモート処理中にコンストラクターが見つからないというエラーは、シリアル化の問題である可能性が最も高くなります (すべてのシリアル化可能なクラスにはパラメーターなしのコンストラクターが必要です)。
リフレクション ツールから見つかったコードは、型キャスト例外をスローする可能性が高くなります。
私はカートとベッドの両方に同意します。これは何か重大な問題があるようです。オプティマイザは私たち全員にとって機能しており、(私が知っている限りでは)そのようなバグは報告されていません。実際に何か間違ったことをしている可能性はありますか?
サイドノート:私も指摘したいと思います System.Collections.Generic.HashSet<T>
これは .Net fx 3.5 に含まれており、まさに Set<>
クラスはそうすべきです。
コードは最近そのサーバーにデプロイされましたか?誰かがあなたの知らないうちにビルドをプッシュした可能性はありますか?ソース管理にアクセスして最新のものを取得し、問題を複製していただけますか?
現時点で、与えられた情報からすると、コンパイラが原因であるとは思えません。
ああ。これが本当に ILMerge に問題がある場合は、このトピックを調査結果に基づいて最新の状態に保ってください。私は COM 相互運用アセンブリを構築する際の重要なステップとして ILMerge を使用しています。