我在库类中调用属性集访问器,该库类在其基类中被标记为抽象。现在在运行时,我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的其他某些属性的 setter / getter ,例如, Size(类型为int!)-它取决于代码中的属性顺序。在前一种情况下,我实现了其他属性的 setter ,因此我忽略了提供的值,因此看不到任何效果。现在,如果它们都具有自动 getter / setter ,则我的代码输出实际上是正确的。

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

最佳答案

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

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

10-06 01:46