IDataErrorInfo的实现,过度使用if语句

本文关键字:if 语句 实现 IDataErrorInfo | 更新日期: 2023-09-27 17:54:35

我真的想不出一个更好的方式来形容我的标题,这可能是对我刚刚所做的最准确的描述。这个问题混合了最佳实践和编码风格。

我基本上有一个WPF应用程序,它使用MVVMLight库和实体框架(6.x)与数据库第一工作流。

从数据库生成的一个POCO类大约有44列,请记住这一点。

用于验证此特定对象。我正在使用实现IDataErrorInfo的部分类扩展POCO对象的功能,如下所示:

public partial class MyClass : IDataErrorInfo { ... }

现在这是可以的,直到你记住这个对象有44个字段。这将给我一个索引器它将有180多行if语句

这对我来说就是糟糕的编程实践。这个索引器的结构是这样的:

public string this[string columnName]
{
    get
    {
        switch (columnName)
        {
            case "Column1":
                if (string.IsNullOrWhiteSpace(Column1))
                    return "A value for Column1 is required.";
                // More if-statements here...
                break;
            case "Column2":
                // Same as above.
                break;
            // There's going to be about another 42 cases here...
        }
        return null;
    }
}

我考虑过的其他事情是将if语句分解成单独的方法,这将减少索引器中的行数,但会引入40多个具有相同结构的方法。

// In the indexer.
switch(columnName)
{
    case "Column1":
        return ValidateColumn1();
        break;
    case "Column2":
        return ValidateColumn2();
        break;
}
// Somewhere a bit further down the class...
private string ValidateColumn1()
{
    if (string.IsNullOrWhiteSpace(Column1))
       return "A value for Column1 is required.";
    // More if-statements...
}
private string ValidateColumn2()
{
    // Ditto.
}

我可以理解,有很多方法可以在WPF/EF中进行验证,例如:

    IDataErrorInfo接口
  • 好友/元数据类
  • 数据注释
  • 绑定验证

,但我只是好奇最好的方法是什么,因为一个200多行的索引器和创建40多个方法/类似乎是一个非常错误的方式去做事情。

我知道我可能在这里问了很多问题,但这是我想要理解的:

  1. 使用这个问题中的第一个代码片段作为示例,使用if语句验证索引器中POCO对象中的每个列是否被认为是良好的实践?对于一个有5列的对象来说,这似乎还可以,但是对于44列的对象来说,它就变得笨拙了,而且是维护的噩梦。(即使这可能是数据库中的正常化问题)
  2. 实现验证的最佳/首选方式是什么,还是取决于程序员的需求?
  3. 是否有其他方法可以解决验证我的POCO对象?我已经看过了FluentValidation库,但是这样做弊大于利,因为我似乎把所有这些不同的库放在一起,希望它们能很好地发挥作用,而它们似乎从来没有这样做过。

IDataErrorInfo的实现,过度使用if语句

这是一种方法(我通常这样做)。我使用EF数据注释(在我的例子中,我用EF数据注释和EF关系流畅接口映射每个实体)。我通常从EntityBase继承标准IDataErrorInfo。这是我的EntityBase

public class EntityBase : IDataErrorInfo
{

    public virtual bool IsValid()
    {
        return GetValidationErrors() == string.Empty;
    }
    protected virtual string GetValidationErrors()
    {
        var vc = new ValidationContext(this, null, null);
        var vResults = new List<ValidationResult>();
        if (!Validator.TryValidateObject(this, vc, vResults, true))
            return vResults.Aggregate("", (current, ve) => current + (ve.ErrorMessage + Environment.NewLine));
        return "";
    }
    protected virtual string GetValidationErrors(string columnName)
    {
        var vc = new ValidationContext(this, null, null);
        var vResults = new List<ValidationResult>();
        if (!Validator.TryValidateObject(this, vc, vResults, true))
        {
            string error = "";
            foreach (var ve in vResults)
            {
                if (ve.MemberNames.Contains(columnName, StringComparer.CurrentCultureIgnoreCase))
                    error += ve.ErrorMessage + Environment.NewLine;
            }
            return error;
        }
        return "";
    }
    string IDataErrorInfo.Error
    {
        get { return GetValidationErrors(); }
    }
    string IDataErrorInfo.this[string columnName]
    {
        get { return GetValidationErrors(columnName); }
    }
}

有些实体需要复杂的属性验证(即交叉属性验证)。在本例中,我重写了虚拟方法,并为实体

添加了特定的验证。