从 Control 派生但隐藏属性
Posted
技术标签:
【中文标题】从 Control 派生但隐藏属性【英文标题】:Deriving from Control but hiding properties 【发布时间】:2011-09-29 07:53:58 【问题描述】:是的,我知道以前有人问过并回答过这个问题,但没有完全解决几个问题。
参考文献
Hiding inherited members Hiding unwanted properties in custom controls基本上,我想从Control
派生,但不暴露某些属性。就我而言,我正在设计一个Container
,它将包含许多Element
s,以编程方式排列。我希望(并且可能要求)Element
派生自 Control
,以便获取所有绘图和事件,但也能够将 Element
对象添加到 @ 987654329@ 的 Children
集合(原因很明显)。
唯一的问题是,如果Element
派生自Control
,那么它的Location
属性就会暴露出来,用户可以很容易地破坏程序化放置。当然,我的直觉是保留 Control
附带的所有好东西并隐藏/禁用 Location
。
我知道以下几点:
这违反了 SOLID Liskov 替换原则(按合同设计) 以前有人问过这个问题 我可以将Control
封装在我的Element
中,并将所有呼叫转发给Control
的所有呼叫
这将是一项荒谬的工作,而且没有真正的收获。
封装的Element
仍然不能与Control
类型兼容,并且不能在Control
的派生形式的许多情况下使用。
我觉得这个(看似)反复出现的问题必须有一些更优雅的解决方案。提前谢谢!
编辑
我看到的唯一方法是:
public class Element : Control
public new Point Location get; private set;
但是,我有一个问题,我的容器类如何设置Element
s 位置?在 C++ 中,人们会使用一个朋友类。我想如果我将这个控件保留在它自己的程序集中,我可以将设置器标记为internal
。
编辑
对于那些想要这样做的人,我的解决方案是:不这样做。相反,我制作了一个自定义对象并自己实现了所有的点击/拖动等。尝试使用控件太复杂了,同时排除了位置等功能。
【问题讨论】:
【参考方案1】:您不能完全阻止确定的程序员更新 Control.Location 属性。使用 new 关键字将更改属性的可访问性,但它仅适用于 Element 和 Element 派生类引用。如果程序员将实例引用强制转换为 Control 的基类,那么他们可以访问原始 Location 属性,从而可以更新值。如果您不关心此解决方法,则只需继续并使用您在问题中显示的覆盖。
要真正防止除您的容器之外的任何人设置位置,那么您必须通过以下方式做更多的工作。对控件Location 或Size 的任何更改实际上都是通过调用虚拟SetBoundsCore 方法来实现的。因此,您可以在您的 Element 类中覆盖此虚拟方法并忽略所有尝试的更改,除非设置了诸如 AllowChange 之类的实例变量。然后在您的容器中,在更新大小/位置之前设置 AllowChange,然后再将其重置。现在更改大小的唯一方法是通过您的容器,或者如果程序员使用鲜为人知的更新属性。
【讨论】:
【参考方案2】:听起来您不是在尝试创建一个替换方法(因为您担心“位置”的可替换性),因此您要么为“位置”创建一对方法,而只是消除它们的事实无法更新底层(因此您正在为不希望影响的属性创建覆盖)或者您忽略 Liskov SOLID 原则,因为这不是您正在做的事情。
【讨论】:
对 - 我并不十分担心 SOLID,但我知道如果我不提及它,它就会被提起。但是你怎么做呢? “Location”是不可覆盖的,如果你把它标记为“private new”,那么基类Location仍然是直接可用的。 理想情况下,是的。但是你不能把它放在需要Control
的地方,比如另一个控件的 Controls
集合。【参考方案3】:
解决此问题的最佳方法是使用内部控制对象。这是完全未经测试的,我还不确定所有界面的可访问性,但这是我开始的方式:
[ComVisibleAttribute(true)]
[ClassInterfaceAttribute(ClassInterfaceType.AutoDispatch)]
public class Element : Component, IDropTarget, ISynchronizeInvoke, IWin32Window,
IBindableComponent, IComponent, IDisposable
private Control _control;
在这里,您可以完全隐藏或公开您选择的任何属性。您的任何接口成员都可以简单地引用内部控件属性。
HTH
【讨论】:
以上是关于从 Control 派生但隐藏属性的主要内容,如果未能解决你的问题,请参考以下文章