在Getter / Setter或者其他地方进行数据验证?
我想知道在getter和setter或者代码中的其他地方进行验证是否是个好主意。
当涉及到优化和加速代码时,这可能会让我们感到惊讶,我认为我们不应该在获取器和设置器中进行验证,而应该在要更新文件或者数据库的代码中进行验证。我错了吗?
解决方案
回答
验证应在验证方法中与获取器或者设置器分开捕获。这样,如果需要在多个组件之间重用验证,则可以使用它。
调用setter时,应使用这种验证服务来清理对象中的输入。这样,我们就知道存储在对象中的所有信息在任何时候都是有效的。
我们不需要对getter进行任何形式的验证,因为有关该对象的信息已经被认为是有效的。
在数据库更新之前不要保存验证!!最好快速失败。
回答
从拥有最具可维护性的代码的角度来看,我认为我们应该在属性的设置器中进行尽可能多的验证。这样,我们将不会缓存或者以其他方式处理无效数据。
毕竟,这就是属性的含义。如果我们拥有的只是一堆属性,例如...
public string Name { get { return _name; } set { _name = value; } }
...他们也可能是田野
回答
这取决于。
通常,代码应该快速失败。如果可以通过代码中的多个点设置该值,并且仅在检索该值后才进行验证,则该错误似乎在进行更新的代码中。如果设置器验证了输入,则我们知道什么代码试图设置无效值。
回答
嗯,为什么类通常包含带有公共获取者/设置者的私有成员的原因之一,正是因为它们可以验证数据。
如果数字大于1到100之间的数字,我肯定会在设置器中放入一些内容进行验证,然后抛出代码捕获的异常。原因很简单:如果我们未在设置器中执行此操作,则每次设置时都必须记住1到100个限制,这会导致代码重复或者忘记时会导致无效状态。
至于性能,我在这里与Knuth在一起:
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."
回答
我们可能想看看Eric Evans的"域驱动设计"。 DDD具有规范的概念:
... explicit predicate-like VALUE OBJECTS for specialized purposes. A SPECIFICATION is a predicate that determines if an object does or does not satisfy some criteria.
我认为快速失败是一回事,另一方面是保持验证逻辑的地方。域是保留逻辑的正确位置,我认为域对象上的规范对象或者验证方法将是一个好地方。
回答
我喜欢实现IDataErrorInfo并将验证逻辑放入其Error和this [columnName]属性。这样,如果我们要以编程方式检查是否存在错误,则可以简单地在代码中测试这些属性中的任何一个,也可以将验证交给Web窗体,Windows窗体或者WPF中的数据绑定。
WPF的" ValidatesOnDataError"绑定属性使此操作特别容易。
回答
@Terrapin,回复:
If all you have is a bunch of [simple public set/get] properties ... they might as well be fields
与字段相比,属性还具有其他优势。它们是更明确的协定,已序列化,可以在以后进行调试,它们是通过继承进行扩展的好地方。更笨拙的语法是一种偶然的复杂性-例如,.net 3.5克服了这一问题。
一种常见的(且有缺陷的)做法是从公共领域开始,然后在"根据需要"的基础上将它们变成属性。这会破坏我们与所有消耗我们课程的人的合同,因此最好从属性开始。
回答
我尝试永远不要让我的对象进入无效状态,因此设置器肯定会进行验证以及更改状态的任何方法。这样,我永远不必担心我正在处理的对象是无效的。如果将方法作为验证边界,则不必担心验证框架和IsValid()方法调用随处可见。