C#如何进行动态绑定?
我有一个关于c语言的动态绑定行为的问题 考虑以下对象层次结构: 反对 System.Windows.Forms.Control 甲级 B类 我的班级 <>可能有额外的类,但这些是我们应该考虑的。对象类和控件类是.NET Framework类。ClassA和ClassB是第三方库类,MyClass是。。。嗯,我的班级。C#如何进行动态绑定?,c#,.net-4.0,C#,.net 4.0,我有一个关于c语言的动态绑定行为的问题 考虑以下对象层次结构: 反对 System.Windows.Forms.Control 甲级 B类 我的班级 可能有额外的类,但这些是我们应该考虑的。对象类和控件类是.NET Framework类。ClassA和ClassB是第三方库类,MyClass是。。。嗯,我的班级。 我已经在MyClass中重写了“Control”的TabStop属性。该属性可能在层次结构中的其他位置被覆盖,但我认为这并不重要。 (MyClass位于另一个程序集中,它是一个vb.n
我已经在MyClass中重写了“Control”的TabStop属性。该属性可能在层次结构中的其他位置被覆盖,但我认为这并不重要。
(MyClass位于另一个程序集中,它是一个vb.net项目) P>最后,请考虑下面的代码。请注意,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实现,或者可能继承自控件。无论哪种情况,它都不是我的代码
有人能解释一下这种行为吗?您实际上没有重写
TabStop
属性,因为
您所做的是通过创建另一个同名属性来“隐藏”它。因此,当您尝试在此处设置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绑定解析名称,因为它不是虚拟的。因此,如果不将对象强制转换为比控件
更派生的对象,则不会看到自己的代码运行
更新:这仍然留下一些悬而未决的问题:
ClassA
,为什么编译器绑定到MyControl.TabStop
?它不应该仍然绑定到控件.TabStop
Control.TabStop
不是虚拟的,为什么编译器允许您将Public Overrides属性TabStop编写为布尔值
我们知道在
Control
和MyControl
之间的层次结构中必须有一些类,它们具有虚拟的TabStop
属性(否则会覆盖MyControl上的。TabStop
将是一个编译器错误)。我们还知道ClassA.TabStop
最终绑定到MyControl.TabStop
。假设在Control
和ClassA
之间的层次结构中没有其他类,那么只有一个逻辑解释:classClassA
定义了一个虚拟的TabStop
属性,该属性将阴影控件。TabStop
您实际上没有覆盖TabStop
属性,因为
您所做的是通过创建另一个同名属性来“隐藏”它。因此,当您尝试在此处设置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绑定解析名称,因为它不是虚拟的。因此,如果不将对象强制转换为比控件
更派生的对象,则不会看到自己的代码运行
更新:这仍然留下一些悬而未决的问题:
如果变量的静态类型是ClassA
,为什么编译器绑定到MyControl.TabStop
?它不应该仍然绑定到控件.TabStop
如果Control.TabStop
不是虚拟的,为什么编译器允许您将Public Overrides属性TabStop编写为布尔值
我们知道在Control
和MyControl
之间的层次结构中必须有一些类,它们具有虚拟的TabStop
属性(否则会覆盖MyControl上的。TabStop
将是一个编译器错误)。我们还知道ClassA.TabStop
最终绑定到MyControl.TabStop
。假设在Control
和ClassA
之间的层次结构中没有其他类,那么只有一个逻辑解释:classClassA
定义了一个虚拟TabStop
属性,该属性将阴影控件。TabStop
我要补充一点,这种混淆是“正常的”对于有Java经验的人来说:默认情况下,所有非静态方法都是虚拟的(除非用private或final标记它们)。谢谢你。但它没有解释第二部分。如果我将赋值设置为“((ClassA)c).TabStop=false”,则MyClass中的代码将运行。为什么?@e-mre:这是一个很好的问题。可能ClassA
使用新的虚拟属性对属性TabStop
进行阴影处理,然后覆盖该属性MyClass
?如果不查看层次结构中所有类的定义,则不能这么说。@xanatos。。。我认为Java方法更有意义。网络行为不符合我头脑中多态性的概念。类的任何用户都希望该类