フォームでメンバーにアクセスすることは、マーシャルバイレファレンスクラスのフィールドであるため、ランタイム例外を引き起こす可能性があります
-
10-10-2019 - |
質問
フォームでメンバーにアクセスすることは、マーシャルバイレファレンスクラスのフィールドであるため、ランタイム例外を引き起こす可能性があります
私はこの警告が何であるかを知っており、それを解決する方法を知っています。
私の質問は、なぜこれがランタイムエラーを引き起こす可能性があるのですか?
解決
おそらく警告CS1690、reproコードについて話している:
public class Remotable : MarshalByRefObject {
public int field;
}
public class Test {
public static void Run() {
var obj = new Remotable();
// Warning CS1690:
Console.WriteLine(obj.field.ToString());
}
}
リモートシナリオでは、test.runメソッドはリモータブルオブジェクトのプロキシで動作します。プロパティ、方法、またはイベントのプロキシを構築することはそれほど問題ではなく、代替品を含む方法を作成するだけの問題です。フィールドは問題ですが、「フック」するものは何もありません。 MBROの場合、JITコンパイラはフィールドに直接アクセスするコードを生成しなくなり、この場合はCLR、JIT_GetField32()に組み込まれたヘルパーメソッドへの呼び出しを注入します。
そのヘルパーは、オブジェクトがプロキシであるかどうかをチェックし、リモート配管を使用してリモート値を取得します。または、そうでない場合は、フィールドに直接アクセスするだけです。ただし、toString()コールを作成するには、値をボックス化する必要があります。これは問題です。ボクシングは、値をプロキシから分離します。箱入りの値が確実になることを保証する方法はありません いつも リモート値の正確なコピー。 toString()メソッドが値を使用して文字列をフォーマットするときはいつでも、jit_getfield32()を呼び出します。
CS1690の回避策はシンプルで、フィールドをプロパティで包む以外に、ローカル変数にフィールド値をコピーするだけです。コードがコピーで動作していることがわかりました。驚きはないので、コンパイラが警告を発する必要はありません。
public static void Run() {
var obj = new Remotable();
var value = obj.field;
Console.WriteLine(value.ToString()); // No warning
}
他のヒント
@Hans-Passantからの提案に加えて、この警告を修正するもう1つの便利な方法は、フィールドをプロパティに変えることだと思います。
public class Remotable : MarshalByRefObject {
public int field;
}
になる可能性があります
public class Remotable : MarshalByRefObject {
public int field { get; set }
}
そして、あなたはもう警告を受けません! (ハンス・パサントはすでにこれについて卓越した説明を持っています、参照してください 彼の投稿)
明らかに、使用しているオブジェクトを常に変更できるとは限りません(例:フィールドが生成される場所:Winforms)。
マーシャルされたオブジェクトの反対側が死んだ場合、参照されるオブジェクトがもう存在しないことを示すランタイムエラーがスローされます。
またはあなたは書くことができます:
var obj = new Remotable();
Console.WriteLine(((int) obj.field).ToString()); // No warning
ここでは、そのキャスト(ボックス化)に対して独自の責任を負います。