C# IDataErrorInfo的实现,过度使用if语句
我真的想不出更好的方式来表达我的标题,这可能是对我刚才所做的最准确的描述。这个问题是最佳实践和编码风格的混合 我基本上有一个WPF应用程序,它使用MVVMLight库和实体框架(6.x)以及数据库优先工作流 从数据库生成的一个POCO类有大约44列,请记住这一点 用于验证此特定对象。我使用实现IDataErrorInfo的分部类扩展POCO对象的功能,如下所示: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 { ... } 现在这是确定的,直到你记
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接口
- 伙伴/元数据类
- 数据注释
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代码>更新:只是尝试将虚拟添加到模板中,但没有任何效果。声称存在歧义。