是的,我知道之前有人问过这个问题并回答过这个问题,但没有一个能完全解决几个问题。
引用资料
本质上,我想派生自 Control
但不公开某些属性。在我的例子中,我正在设计一个 Container
,它将包含许多以编程方式排列的 Element
。我希望(并且可能要求)Element
派生自 Control
,以便获得所有绘图和事件,但也能够将 Element
对象添加到 Container
的 Children
集合(原因很明显)。
唯一的问题是,如果 Element
派生自 Control
,那么它的 Location
属性就会暴露,用户可以很容易地破坏程序放置。自然地,我的直觉是保留所有随 Control
一起出现的好东西,并隐藏/禁用 Location
。
我知道以下内容:
- 这违反了 SOLID Liskov 替换原则(按契约(Contract)设计)
- 之前有人问过
- 我可以将
Control
封装在我的Element
中,并将所有调用转发给Control
的调用- 这将是一项荒谬的工作量,而且没有任何实际 yield 。
- 封装的
Element
仍然与Control
类型不兼容,并且在许多情况下不能使用Control
的派生形式会。
我觉得必须有一些更优雅的解决方案来解决这个(看似)反复出现的问题。提前致谢!
编辑
我认为实现此目的的唯一方法是:
public class Element : Control
{
public new Point Location { get; private set; }
}
但是,我的问题是,我的容器类如何设置 Element
的位置?在 C++ 中,人们会使用友元类。我想如果我将这个控件保留在它自己的程序集中,我可以将 setter 标记为 internal
。
编辑
对于那些想做这件事的人,我的解决方案是:不做。相反,我制作了一个自定义对象并自己实现了所有的点击/拖动等操作。尝试使用控件太复杂了,同时排除了位置等功能。
最佳答案
您不能完全阻止 Control.Location 属性被坚定的程序员更新。使用 new 关键字将更改属性的可访问性,但它仅适用于 Element 和 Element 派生类引用。如果程序员将实例引用转换为 Control 的基类,则他们可以访问原始的 Location 属性,因此可以更新值。如果您不关心此解决方法,则只需继续并使用您在问题中显示的覆盖。
要真正防止除您的容器之外的任何人设置位置,您必须通过以下方式做更多的工作。对控件 Location 或 Size 的任何更改实际上都是通过调用虚拟 SetBoundsCore 方法来实现的。因此,您可以在 Element 类中重写此虚拟方法并忽略所有尝试的更改,除非设置了实例变量(如 AllowChange)。然后在您的容器中,您在更新大小/位置之前设置 AllowChange,然后再将其重置。现在更改大小的唯一方法是通过您的容器,或者如果程序员使用鲜为人知的更新属性。
关于c# - 从 Control 派生但隐藏属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6591849/