Digital Nirvana: Где заканчивается callvirt несуществующего метода?

Я вызываю свойство set-accessor в классе библиотеки, который в своем базовом классе помечен как абстрактный. Теперь во время выполнения я принудительно приложение запускается против другой версии библиотеки, где класс реализует только базовые интерфейсы базового класса, но isn 't, полученных из него.

Интересно, что .NET будет запускать код, но установка свойства не имеет никакого эффекта. Что происходит за кулисами?

Код нарушения:

MyDbParameter param = new MyDbParameter();
param.ParameterName = "p";
Console.Out.WriteLine("ParameterName: " + param.ParameterName);

Библиотека 2.0 (скомпилировано)

public sealed class MyDbParameter : System.Data.Common.DbParameter
{
    public override string ParameterName
    {
       get { return _name; }
       set { _name = value; }
    }
    //...
}

Библиотека 1.0 (запустите)

public sealed class MyDbParameter : MarshalByRefObject, IDbDataParameter, IDataParameter
{
    public string ParameterName
    {
        get { return _name; }
        set { _name = value; }
    }
    //...
}

Глядя на MSIL вызывающего кода, я предполагаю, что виртуальный вызов разрешен через MetodTable базового класса:

IL_0001: newobj instance void [Library]Library.MyDbParameter::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldstr "p"
IL_000d: callvirt instance void [System.Data]System.Data.Common.DbParameter::set_ParameterName(string)

Но базовый класс не существует при запуске кода - и не DbParameter.set_ParameterName(). Как возможно, что .NET не жалуется на это? Какой метод действительно вызван?


UPDATE:

Как было предложено Samuel, я декомпилировал класс System.Data.Common.DbParameter и принял его в обеих моих библиотеках. Поведение воспроизводится независимо от того, что я получил от MarshalByRefObject или прокомментировал все это - таким образом, я считаю, что я фальсифицировал ответ Мейсона.

Но во время процесса я обнаружил, что происходит: на самом деле это сеттер/получатель другого свойства MyDbParameter в библиотеке 1, что называется, например. Size (который имеет тип int!) - он зависит от порядка свойств в коде. В предыдущем случае я реализовал сеттеры других свойств, чтобы игнорировать предоставленные значения, поэтому я не видел никакого эффекта. Теперь, если у всех из них есть автоматические getters/seters, вывод моего кода действительно правильный.

Остается вопрос: почему .NET не жалуется на недостающий метод во время выполнения?

Ответ 1

Я считаю, что ваша нирвана заполнена MarshalByRefObjects. Они обрабатываются уникально каркасом, поскольку он обеспечивает доступ ко всем им, чтобы рассматривать их как прокси-серверы для удаленных объектов. MBRO не может фактически выполнить запрос на нарушение кода (поскольку ваш класс v1 не поддерживает DbParameter::set_ParameterName), поэтому он ведет длинный путь в никуда. Он не рассматривается как MissingMethodException, поскольку MBRO обычно пропускают запрашиваемые элементы, поэтому время выполнения намного более мягкое.

Однако, если вы попытались изменить свой код нарушения для того, чтобы сбрасывать param как IDbDataParameter перед установкой свойства, я полагаю, что это сработает, поскольку оба v1 и v2 поддерживают этот интерфейс.