我在库类中调用属性集访问器,该库类在其基类中被标记为抽象。现在在运行时,我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)。