数字涅槃:不存在的方法的调用者最终在哪里

本文关键字:在哪里 调用者 方法 不存在 数字 涅槃 | 更新日期: 2023-09-27 17:55:11

我在库类上调用属性集访问器,该库类在其基类中标记为抽象。现在,在运行时,我强制应用程序针对库的另一个版本运行,其中类仅实现基类的底层接口,但不是从基类派生的。

有趣的是,.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 怎么可能不抱怨这一点?实际调用哪种方法?


更新:

按照 Samuel 的建议,我已经反编译了类System.Data.Common.DbParameter,并在我的两个库中采用了它。无论我从MarshalByRefObject中得出什么或注释掉所有内容,这种行为都会重现 - 因此我相信我已经伪造了梅森的答案。

但在这个过程中,我发现了会发生什么:实际上,它是库 1 中MyDbParameter的其他一些属性的设置者/获取者,例如 Size(类型为 int!) - 这取决于代码中的属性顺序。在前面的情况下,我实现了其他属性的 setter,以便忽略提供的值,因此我看不到任何效果。现在,如果它们都有自动getter/setter,那么我的代码输出实际上是正确的。

问题仍然存在:为什么 .NET 在运行时不抱怨缺少方法?

数字涅槃:不存在的方法的调用者最终在哪里

我相信

你的涅槃充满了MarshalByRefObjects.它们由框架唯一处理,因为它检测对它们的所有访问,以便将它们视为远程对象的代理。MBRO 实际上无法满足违规代码的请求(因为您的 v1 类不支持 DbParameter::set_ParameterName ),因此它正在走很长的路。它不被视为MissingMethodException,因为 MBRO 通常缺少请求的成员,因此运行时要宽松得多。

但是,如果您在设置属性之前尝试将有问题的代码更改为将 param 转换为IDbDataParameter,我想它会起作用,因为 v1 和 v2 都支持该接口。