关于优化:在Getter / Setter或其他地方进行数据验证?

关于优化:在Getter / Setter或其他地方进行数据验证?

Data verifications in Getter/Setter or elsewhere?

我想知道在getter和setter或代码中的其他地方进行验证是否是一个好主意。

当涉及到优化和加速代码时,这可能会让您感到惊讶,我认为您不应该在获取器和设置器中进行验证,而应该在要更新文件或数据库的代码中进行验证。 我错了吗?


好的,为什么类通常包含带有公共获取者/设置者的私有成员的原因之一,恰恰是因为它们可以验证数据。

如果您的数字大于1到100之间的数字,我肯定会在setter中放一些东西来验证它,然后可能抛出代码捕获的异常。原因很简单:如果您未在设置器中执行此操作,则每次设置时都必须记住1到100个限制,这会导致代码重复或当您忘记它时会导致无效状态。

至于性能,我在这里与Knuth在一起:

"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."


@Terrapin,回复:

If all you have is a bunch of [simple
public set/get] properties ... they
might as well be fields

与字段相比,属性还具有其他优势。它们是更明确的协定,已序列化,可以稍后进行调试,它们是通过继承进行扩展的好地方。语法较笨拙是一种偶然的复杂性,例如.net 3.5克服了这一问题。

一种常见的(且有缺陷的)做法是从公共领域开始,然后在"根据需要"的基础上将它们变成属性。这会破坏与任何消耗您课程的人的合同,因此最好从属性开始。


这取决于。

通常,代码应该快速失败。如果可以通过代码中的多个点设置该值,并且仅在检索该值后才进行验证,则该错误似乎在进行更新的代码中。如果设置器验证了输入,则您知道什么代码试图设置无效值。


从拥有最具可维护性的代码的角度来看,我认为您应该在属性的设置器中进行尽可能多的验证。这样,您将不会缓存或以其他方式处理无效数据。

毕竟,这是属性的含义。如果您拥有的只是一堆属性,例如...

1
2
3
4
5
6
7
8
9
10
11
public string Name
{
    get
    {
        return _name;
    }
    set
    {
        _name = value;
    }
}

...他们可能是领域


我尝试永远不要让我的对象进入无效状态,因此设置器肯定会进行验证以及更改状态的任何方法。这样,我不必担心正在处理的对象是无效的。如果将方法作为验证边界,那么您就不必担心验证框架和IsValid()方法调用随处可见。


我喜欢实现IDataErrorInfo并将验证逻辑放入其Error和this [columnName]属性。这样,如果您要以编程方式检查是否存在错误,则可以简单地在代码中测试这些属性中的任何一个,或者可以将验证交给Web窗体,Windows窗体或WPF中的数据绑定。

WPF的" ValidatesOnDataError"绑定属性使此操作特别容易。


您可能想看看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.

我认为快速失败是一回事,另一方面是保持验证逻辑的地方。域是保留逻辑的正确位置,我认为您的域对象上的规范对象或验证方法将是一个好地方。


验证应在验证方法中与获取器或设置器分开捕获。这样,如果需要在多个组件之间重用验证,则可以使用它。

调用setter时,应使用这种验证服务来清理对象中的输入。这样,您知道存储在对象中的所有信息始终有效。

您不需要对getter进行任何形式的验证,因为有关该对象的信息已经被认为是有效的。

在数据库更新之前,不要保存您的验证!!最好快速失败。


推荐阅读