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

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

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

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

4 ответов


вы, вероятно, говорите о предупреждении 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());
    }
}

в сценарии удаленного взаимодействия тест.Метод Run будет работать с прокси-сервером удаленного объекта. Создание прокси для свойства, метода или события не является большой проблемой, просто вопрос создания 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

здесь вы берете на себя ответственность за то, что бросил (распаковка).