Доступ к члену в форме может вызвать исключение во время выполнения, поскольку это поле класса маршала по ссылке - PullRequest
14 голосов
/ 14 ноября 2010

Доступ к члену в форме может вызвать исключение времени выполнения, потому что это поле класса маршала по ссылке

Я знаю, что это за предупреждение, и знаю, как его решить.

Мой вопрос: почему это может вызвать ошибку во время выполнения?

Ответы [ 4 ]

25 голосов
/ 14 ноября 2010

Возможно, вы говорите о предупреждении CS1690, код повторения:

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 будет работать с прокси объекта Remotable.Создание прокси для свойства, метода или события не является большой проблемой, просто вопрос создания MethodTable, который содержит заменители.Поля - проблема, однако, нечего «зацепить».Для MBRO JIT-компилятор больше не генерирует код для прямого доступа к полю, он вводит вызов вспомогательного метода, встроенного в CLR, в данном случае JIT_GetField32 ().

Этот помощник проверяет, является ли объектпрокси и использует удаленное соединение для получения удаленного значения, если это так.Или просто получает доступ к полю напрямую, если это не так.Однако выполнение вызова ToString () требует, чтобы значение было упаковано.Это проблема, бокс изолирует значение от прокси.Невозможно гарантировать, что в штучной упаковке значение всегда является точной копией удаленного значения.Повторный вызов JIT_GetField32 () каждый раз, когда метод ToString () использует значение для форматирования строки, невозможен.

Обходной путь для CS1690 прост, за исключением переноса поля со свойством, просто скопируйте значение поля влокальная переменная.Теперь совершенно ясно, что код работает с копией, и ничего удивительного в этом нет, поэтому компилятору не нужно выдавать предупреждение.

public static void Run() {
    var obj = new Remotable();
    var value = obj.field;
    Console.WriteLine(value.ToString());     // No warning
}
4 голосов
/ 27 октября 2015

В дополнение к предложению @ hans-passant, я думаю, еще один полезный способ исправить это предупреждение - превратить поле в свойство.

public class Remotable : MarshalByRefObject {
    public int field;
}

может стать

public class Remotable : MarshalByRefObject {
    public int field { get; set }
}

и вы больше не получаете никаких предупреждений!(У Ханса Пассанта уже есть превосходное объяснение этому, см. его пост )

Очевидно, что вы не всегда можете изменить объект, с которым работаете (пример: WinForms, где поля создаютсявам), так что вам может потребоваться использовать временную переменную.

0 голосов
/ 01 октября 2017

Или вы можете написать:

var obj = new Remotable();

Console.WriteLine(((int) obj.field).ToString());     // No warning

Здесь вы берете на себя ответственность за этот состав (распаковка).

0 голосов
/ 14 ноября 2010

Если другая сторона маршаллированного объекта умерла, она выдаст ошибку времени выполнения о том, что упомянутый объект больше не существует.

...