数字涅槃:不存在的方法的调用者最终在哪里
本文关键字:在哪里 调用者 方法 不存在 数字 涅槃 | 更新日期: 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 都支持该接口。