我正在基于TextBox在C#中编写自定义控件。我希望我的控件的Text属性是只读的(因为在文本框中只允许某些值,我不希望调用程序能够在其中放置无效值。)
我不知道该怎么做。如果我使用公共覆盖Text {},编译器会插入默认的get和set访问器。如果我注释掉set访问器,则代码编译并运行,我假设这意味着正在使用基本访问器。如果我将readonly放在我的属性的定义中,编译器会抛出错误。
非常感谢任何帮助。
答案 0 :(得分:9)
这里的问题是,通过尝试将读/写属性设置为只读,您违反了基类的合同。您的基类明确声明可以检索和修改此属性。派生类不能破坏其基类的契约,否则多态会失败。请记住,如果B派生自A,则接受A对象的任何地方,B必须执行。
如果派生类不应该这样,那么我首先会质疑设计 - 这真的应该来自基类吗?这真的是一种“是一种”关系吗?
假设我们通过了那个测试而且确实应该派生出来,一种方法 - 我个人不喜欢,但无论如何也会分享 - 可能只是让setter抛出异常。我个人不喜欢这样,它仍然违反了合同,并且在使用派生类时感觉过度认知摩擦,但如果你真的有这样的理由那么这样做......好吧......好吧,我猜。但是你要确定你知道为什么你要乱搞这个。
但回到第一点:从设计的角度来看,这是否真的是派生类是正确答案的场景?没有看到你的代码,我的直觉反应是否定的。
在我最初的阅读中,我错过了我们在这里讨论UI控件的事实。我支持我在上面编辑的内容,在一般属性覆盖案例中。但是,在UI控件的情况下,多态性机会(我希望)会有所限制,并且需要可能证明这个设计是合理的,那么我的建议是让Text属性setter抛出异常。
在我看来,更好的设计是构图。创建用户控件,使用Dock = Fill将TextBox添加到用户控件设计图面,然后公开一个只读的新Text属性。您现在也可以只公开您真正想要的属性。
答案 1 :(得分:3)
您必须通过使用“new”关键字声明Text来隐藏基本属性。
public new string Text { get; private set;}
您无法使用覆盖更改访问权限,因此您无法使用覆盖关键字,如您所见。这种方式将“隐藏”Text的基本实现,这并不总是一个好主意,但只要您知道它将对您有用的风险。
答案 2 :(得分:2)
public new string Text { get; private set;}
答案 3 :(得分:1)
我认为John Rudy在这里可能有一点意义。继承不是一切的答案。如果您需要做的是限制文本框以便只接受有效值,那么您可能希望使用验证控件来确保只允许某些值。
通过这种方式,您可以利用Microsoft为我们提供的组件获得您想要的行为。没有必要的继承类。
编辑:如果您每次想要修改UI控件的行为时创建子类,您将很快掌握一个不守规矩的继承层次结构。出于这个原因,我建议你考虑组合来修改UI控件。
答案 4 :(得分:1)
除了其他人对整体设计问题的评论(John Ruby很好地解释),你总是可以覆盖setter来做什么或者抛出异常。
答案 5 :(得分:1)
我不认为阴影属性是正确的答案,因为通过基地的任何引用仍然有效。由于属性是虚拟的,因此您可以覆盖它并实现忽略更改或引发异常的setter。我知道它看起来不太干净,但它具有实际工作的优势。
修改的
看起来Yuriy Faktorovich在我可以做出同样的建议之前。