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

C# IDataErrorInfo的实现,过度使用if语句,c#,entity-framework,validation,mvvm-light,C#,Entity Framework,Validation,Mvvm Light,我真的想不出更好的方式来表达我的标题,这可能是对我刚才所做的最准确的描述。这个问题是最佳实践和编码风格的混合 我基本上有一个WPF应用程序,它使用MVVMLight库和实体框架(6.x)以及数据库优先工作流 从数据库生成的一个POCO类有大约44列,请记住这一点 用于验证此特定对象。我使用实现IDataErrorInfo的分部类扩展POCO对象的功能,如下所示: public partial class MyClass : IDataErrorInfo { ... } 现在这是确定的,直到你记

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

我基本上有一个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多个方法/类似乎是一个非常错误的方法

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

  • 以讨论中的第一个代码段为例,使用if语句验证索引器中POCO对象中的每一列是否被认为是良好的做法? 对于一个有5列的对象来说,这似乎是可以的,但如果有44列,它将变得非常笨拙,并且成为维护的噩梦。(即使这可能是数据库中的正常化问题。)
  • 实现验证的最佳/首选方法是什么,还是取决于程序员的要求
  • 是否有其他方法可以验证我的POCO对象?我看过FluentValidation库,但这弊大于利,因为我似乎把所有这些不同的库放在一起,希望它们能一起玩得很好,但它们似乎从来没有这样做过
  • 提前感谢。

    这是一种方法(我通常这样做)。 我使用EF数据注释(在我的例子中,我使用EF数据注释映射每个实体,并使用EF fluent接口映射关系)。 我通常从具有标准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); }
        }
    
    }
    
    公共类EntityBase:IDataErrorInfo
    {
    公共虚拟bool IsValid()
    {
    返回GetValidationErrors()==string.Empty;
    }
    受保护的虚拟字符串GetValidationErrors()
    {
    var vc=新的ValidationContext(this,null,null);
    var vResults=新列表();
    if(!Validator.TryValidateObject(this,vc,vResults,true))
    返回vResults.Aggregate(“,(current,ve)=>current+(ve.ErrorMessage+Environment.NewLine));
    返回“”;
    }
    受保护的虚拟字符串GetValidationErrors(字符串columnName)
    {
    var vc=新的ValidationContext(this,null,null);
    var vResults=新列表();
    if(!Validator.TryValidateObject(this,vc,vResults,true))
    {
    字符串错误=”;
    foreach(vResults中的var ve)
    {
    if(ve.MemberNames.Contains(columnName,StringComparer.CurrentCultureIgnoreCase))
    error+=ve.ErrorMessage+Environment.NewLine;
    }
    返回误差;
    }
    返回“”;
    }
    字符串IDataErrorInfo.Error
    {
    获取{return GetValidationErrors();}
    }
    字符串IDataErrorInfo。此[string columnName]
    {
    获取{返回GetValidationErrors(columnName);}
    }
    }
    

    有些实体需要复杂的属性验证(即跨属性验证)。在本例中,我覆盖了虚拟方法,并为IDataErrorInfo的实体添加了特定的验证

    ,使用字典来存储特定属性的错误如何?至少这似乎是新INotifyDataErrorInfo接口的首选方式:@vesan,我已经查看了该链接,我可以澄清一下吗,我是否需要显式地为我的POCO对象中的属性编写get/set访问器,以便在T4模板生成每个属性时使用该接口:
    public datatype PropertyName
    ,或者更确切地说,我是否需要以某种方式更改模板本身?我不确定生成的代码是什么样子,但可以,其思想是每次属性更改时都会运行验证,这需要一个自定义集访问器。@vesan,更改模板以将属性写入虚拟属性是否合适?i、 e.
    公共虚拟字符串MyProperty更新:只是尝试将虚拟添加到模板中,但没有任何效果。声称存在歧义。