gpt4 book ai didi

c# - 数字必杀技 : Where does a callvirt of a non-existent method end up?

转载 作者:可可西里 更新时间:2023-11-01 08:48:55 27 4
gpt4 key购买 nike

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

有趣的是,.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 派生还是将其全部注释掉,该行为都会重现 - 在此我相信我伪造了 Mason's回答。

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

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

最佳答案

我相信您的必杀技充满了 MarshalByRefObjects。它们由框架独特地处理,因为它检测所有对它们的访问,以便将它们视为远程对象的代理。 MBRO 实际上无法满足有问题的代码的请求(因为您的 v1 类不支持 DbParameter::set_ParameterName),因此它走的路很长。它不被视为 MissingMethodException,因为 MBRO 通常缺少请求的成员,因此运行时要宽松得多。

但是,如果您在设置属性之前尝试更改违规代码以将参数转换为 IDbDataParameter,我想它会起作用,因为 v1 和 v2 都支持该接口(interface)。

关于c# - 数字必杀技 : Where does a callvirt of a non-existent method end up?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14473315/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com