我有关于c#语言的动态绑定行为的这个问题.
考虑以下对象层次结构:
宾语
System.Windows.Forms.Control的
ClassA的
ClassB的
我的课
中间可能还有其他类,但这些是我们应该考虑的.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
Run Code Online (Sandbox Code Playgroud)
最后,请考虑以下代码.请注意,myControlCollection中的某些对象是MyClass类型,其他对象不是:
foreach (Control c in myControlCollection)
{
if (c is ClassA)
{
if (((ClassA)c).Properties.ReadOnly) c.TabStop = false;
}
}
Run Code Online (Sandbox Code Playgroud)
现在问题是:我在MyClass的TabStop属性的setter方法中设置了一个断点.
如果代码如上所述运行,则不会对集合中的任何对象触发断点.
如果我改变行...
((ClassA)c).TabStop = false;
... visual studio在MyClass声明中击中了断点.
这让我很困惑.当通过"Control"类型的变量调用属性时,为什么不会触发断点.即使变量是Control类型,实际对象的类型是MyClass,所以我认为应该触发断点.
第二,如果在通过Control类型的变量调用时没有命中,为什么在我将变量转换为ClassA时它会命中.我没有将它转换为MyClass,我将它转换为基类,它可能有自己的TabStop实现,或者可能从Control继承.无论哪种情况,都不是我的代码.
任何人都可以解释一下这种行为吗?
您实际上没有覆盖该TabStop属性,因为它不是虚拟的.
你所做的是通过创建具有相同名称的另一个属性来"隐藏"它.因此,当您尝试在Control.TabStop此处设置时,将执行不同的属性设置器:
// The static type of c is Control!
if (((ClassA)c).Properties.ReadOnly) c.TabStop = false;
Run Code Online (Sandbox Code Playgroud)
当你在这里设置它:
// The static type is now ClassA
((ClassA)c).TabStop = false;
Run Code Online (Sandbox Code Playgroud)
当您引用该属性时,编译器使用静态绑定解析名称,因为它不是虚拟的.因此,如果您不将对象转换为更多派生的对象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,则只有一个逻辑解释:class ClassA定义了一个虚拟TabStop属性Shadows Control.TabStop.