2

我想对我的业务代码进行验证。我正在考虑两种方法来做到这一点。

一,按以下方式对我的类属性设置器进行验证

class Student{
    public string Name{
        get { return _name; }
        set {
            if (value.IsNullOrEmpty) throw exception ...
        }
    } 
} 

现在,这种方法的问题在于,每次分配 Name 时都会运行验证代码,而我们可能不需要,例如用数据库中的数据填充它时。

两个,我更喜欢,将静态方法放在这些实体类上,比如

class Student {
    public **static** void ValidateName(**string name**) {
        if (string.IsNullorEmpty(name)) 
        {
            throw ...
        }
        ...
    } 

请注意,我使用的是静态方法而不是实例方法,例如

class Student{
    public void Validate() {
        // validation logic on instance properties
        if (string.IsNullorEmpty(Name)) 
        {
            throw ...
        }

        ...
    } 

是因为我并不总是传入一个 Student obj,我确实经常将原始类型(如字符串名称)传递给一个方法,比如

public static FindStudentByName(string name)
{
   // here I want to first do validation
   Student.ValidateName(name);

   // query DB
   ...
}

如果我确实通过了学生 obj,那么我当然可以

public static AddStudent(Student s)
{
    // call the instance method
    s.Validate();
}

现在,我想让事情变得非常简单,所以我不想采用以下任何一种方法

  1. 在属性上使用属性,例如 [StringLength(25)]。

    一,因为这需要反射并影响性能,所以有一些技巧可以降低性能,但我还是想让它越简单越好。

    第二,我希望我的网站能够在 Medium Trust 中运行。据我了解,反思需要完全信任。

  2. 使用那里的任何验证块,例如 MS。在 CodePlex 上找到企业库等。

现在,我想听听你对此的看法,

我要采用的方法有哪些潜在问题?
这种方法会比其他方法性能更好、更易读、更容易维护吗?

您如何在中间层进行验证?

谢谢一堆!

射线。

4

3 回答 3

4

我使用规则引擎在中间层执行域验证,与此处所写的非常相似。一个朋友的项目使用类似于您在后一个示例中提出的方法,最终结果是不可维护的(脆弱,难以实现通用验证 UI)。规则引擎方法是可维护的,因为它将所有验证和持久性规则本地化在一个组织良好的位置,并将每个规则作为一个完全成熟的类 - 但在域类上公开验证,类似于您提出的。有些人喜欢动态编译,因此他们将它们存储在数据库中以进行高级部署后配置;在我的情况下,我喜欢它们的编译时间检查,因此在静态类上公开了带有 lambda 的规则定义。

我知道这不符合你想要做的,但是问我会怎么做并说其他方法不够简单就像说“你怎么能写出可靠的代码,我想保持简单所以单元测试是不可能的。” 对我来说,将每个规则视为自己的类是好的,因为它更易于维护和记录,尽管实现起来更复杂。

于 2008-10-30T18:33:38.437 回答
1

选项二实际上并不强制执行验证,至少在您手动调用 validate 的情况下不会。因此,您的对象的消费者可能会违反规则。

我个人会使用类似于您的第一个示例的内容,因为它可以确保所有数据都是有效的。这是对数据库方面的额外检查,但据我所知,通常没什么大不了的。

于 2008-10-30T18:20:18.667 回答
1

您建议的方法似乎表明不应始终应用该组验证。没关系。我已经看到了很多我们“大多数时候”想要的规则和验证,但并非总是如此。所以,问题变成了“您希望何时应用这些验证”?

比如说,你有一些你总是想要应用的验证,还有一些你只想在......我不知道......你即将保存到存储(数据库)时验证。在这种情况下,始终应用的检查应该在属性中(请参阅下面的更多内容),并且仅在您要保存到存储时应用的检查应该在方法中(可能沿行命名 ' VerifyRulesForStorage') 将在适当时调用(例如,在您的“SaveToStorage”方法中间)。

我认为值得考虑的一件事是,当您在多个实体之间进行相同的验证时,您可能会发生重复。无论是在属性中,还是在“VerifyRulesForStorage”方法中,您都可能会在许多地方、许多类中进行相同的检查(例如:String.IsNullOrEmpty 或 CheckItsANumber 或 CheckItsOneOfTheAcceptedValues 等)。当然,您可以通过继承(例如,您的所有实体都从具有实现每种检查类型的方法的基实体类继承)或组合(可能是更好的方法,以便您的实体的类树由其他驱动,更合适的考虑因素,例如:您的所有实体都有一个 Validator 对象来实现所有这些检查)。无论哪种方式,您都可能希望远离静态方法,

在我们的系统中,我们实际上有描述验证规则的元数据。类的属性名称用于检索正确的元数据,然后告诉系统应用哪些规则。然后,我们有一个验证器对象,它通过工厂实例化正确类型的对象以实际执行验证(例如,我们有一个实现 IsRequiredString 规则的类,一个实现 IsNumber 规则等)。听起来很复杂,但在像我们这样的 lrge 系统中,这绝对是值得的。

最后,现成的库可能是一个不错的选择。在我们的情况下,它们不是因为我们有特殊要求 - 但总的来说.. 使用其他人开发(并将支持)的轮子比构建自己的轮子有好处(相信我,我喜欢在我的时候重建轮子可以..我只是说在某些情况下,每种方法都比另一种更好)。

于 2008-10-30T18:37:54.827 回答