我有一个关于 C# 语言的动态绑定(bind)行为的问题。
考虑以下对象层次结构:
object
System.Windows.Forms.Control
ClassA
ClassB
block 引用> block 引用> block 引用> block 引用>MyClass
中间可能还有其他类,但这些是我们应该考虑的。对象和控件类是 .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。无论哪种情况,这都不是我的代码。有人可以解释一下这种行为吗?
最佳答案
您实际上并未覆盖 TabStop
属性,因为 it is not virtual .
您所做的是通过创建另一个同名的属性来“隐藏”它。因此,当您尝试在此处设置 Control.TabStop
时,会执行不同的属性 setter :
// 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;
当您引用属性时,编译器会使用静态绑定(bind)来解析名称,因为它不是虚拟的。因此,如果您不将该对象转换为比 Control
更派生的对象,您将不会看到自己的代码运行。
更新:这仍然留下一些悬而未决的问题:
- 如果变量的静态类型是
ClassA
,为什么编译器会绑定(bind)到MyControl.TabStop
?难道它不应该仍然绑定(bind)到Control.TabStop
吗? - 如果
Control.TabStop
不是虚拟的,为什么编译器允许您编写Public Overrides Property TabStop As Boolean
?
我们知道 Control
和 MyControl
之间的层次结构中必须存在某个类,并且具有虚拟 TabStop
属性(否则 MyControl.TabStop
上的 Overrides
将出现编译器错误)。我们还知道 ClassA.TabStop
最终绑定(bind)到 MyControl.TabStop
。假设 Control
和 ClassA
之间的层次结构中没有其他类,则只有一个逻辑解释:类 ClassA
定义了一个虚拟
属性。Shadows
Control.TabStop
的 >TabStop
关于c# - C#如何进行动态绑定(bind)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7358282/