我有关于c#语言动态绑定行为的问题。
考虑以下对象层次结构:
对象
System.Windows.Forms.Control
ClassA
ClassB
MyClass
可能会有其他类,但这些是我们应该考虑的。 Object和Control类是.NET Framework类。 ClassA和ClassB是第三方库类,MyClass是......好吧,我的班级 我在MyClass中重写了“Control”的TabStop属性。该属性可能会在层次结构中的其他位置被覆盖,但我认为这并不重要 (MyClass在另一个程序集中,这是一个vb.net项目)
Public Overrides Property TabStop As Boolean
Get
Return MyBase.TabStop
End Get
Set(value As Boolean)
MyBase.TabStop = value
End Set
End Property
最后,请考虑以下代码。请注意,myControlCollection中的某些对象是MyClass类型,其他对象不是。:
foreach (Control c in myControlCollection)
{
if (c is ClassA)
{
if (((ClassA)c).Properties.ReadOnly) c.TabStop = false;
}
}
现在问题是: 我在MyClass的TabStop属性的setter方法中设置了一个断点。
如果代码按上面给出的那样运行,则不会对集合中的任何对象点击断点。
如果我将行更改为...
((ClassA)c).TabStop = false;
... visual studio命中MyClass声明中的断点。
这让我很困惑。当通过“Control”类型的变量调用属性时,为什么不会触发断点。即使变量是Control类型,实际对象也是MyClass类型,所以我认为断点应该被击中。
第二,如果在通过Control类型的变量调用时没有命中,为什么在我将变量转换为ClassA时它会命中。我没有将它转换为MyClass,我将它转换为基类,它可能有自己的TabStop实现,或者可能从Control继承。无论哪种情况,都不是我的代码。
有人可以解释一下这种行为吗?
答案 0 :(得分:5)
您实际上并未覆盖TabStop
属性,因为it is not virtual。
您所做的是通过创建具有相同名称的另一个属性来“隐藏”它。因此,当您尝试在此处设置Control.TabStop
时,会执行不同的属性设置器:
// The static type of c is Control!
if (((ClassA)c).Properties.ReadOnly) c.TabStop = false;
当你在这里设置时:
// The static type is now ClassA
((ClassA)c).TabStop = false;
当您引用该属性时,编译器使用 static 绑定解析名称,因为它不是虚拟的。因此,如果您不将对象强制转换为比Control
更加派生的对象,则不会看到自己的代码运行。
更新:这仍有一些悬而未决的问题:
MyControl.TabStop
,为什么编译器会绑定到ClassA
?它不应该仍然绑定到Control.TabStop
?Public Overrides Property TabStop As Boolean
不是虚拟的话,为什么编译器会让你写Control.TabStop
?我们知道Control
和MyControl
之间的层次结构中必须有某些类,并且具有虚拟TabStop
属性(否则为Overrides
在MyControl.TabStop
上将是编译器错误)。我们也知道ClassA.TabStop
最终会绑定到MyControl.TabStop
。假设Control
和ClassA
之间的层次结构中没有其他类,则只有一个逻辑解释:类ClassA
定义TabStop
的虚拟Shadows
属性} Control.TabStop
。