Доступ к члену в форме может вызвать исключение во время выполнения, поскольку он является полем класса маршала по ссылке
Я знаю, что это за предупреждение, и знаю, как его решить.
Мой вопрос: почему это может привести к ошибке выполнения?
Доступ к члену в форме может вызвать исключение во время выполнения, поскольку он является полем класса маршала по ссылке
Я знаю, что это за предупреждение, и знаю, как его решить.
Мой вопрос: почему это может привести к ошибке выполнения?
Вероятно, вы говорите о предупреждении 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
}
В дополнение к предложению @hans-passant, я думаю, что еще один полезный способ исправить это предупреждение - это превратить ваше поле в свойство.
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
Здесь вы берете на себя ответственность за этот прилив (распаковка).