gpt4 book ai didi

C# 验证 : IDataErrorInfo without hard-coded strings of property name?

转载 作者:可可西里 更新时间:2023-11-01 08:23:03 25 4
gpt4 key购买 nike

实现 IDataErrorInfo 的最佳做法是什么?无论如何都可以在没有属性名称硬编码字符串的情况下实现它?

最佳答案

通用验证例程的基类

您可以使用 DataAnnotations如果您在 IDataErrorInfo 实现中做了一些 futzing。例如,这是我经常使用的基本 View 模型(来自 Windows 窗体,但您可以推断):

public class ViewModelBase : IDataErrorInfo, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

public SynchronizationContext Context
{
get;
set;
}

public bool HasErrors
{
get
{
return !string.IsNullOrWhiteSpace(this.Error);
}
}

public string Error
{
get
{
var type = this.GetType();
var modelClassProperties = TypeDescriptor
.GetProperties(type)
.Cast();

return
(from modelProp in modelClassProperties
let error = this[modelProp.Name]
where !string.IsNullOrWhiteSpace(error)
select error)
.Aggregate(new StringBuilder(), (acc, next) => acc.Append(" ").Append(next))
.ToString();
}
}

public virtual string this[string columnName]
{
get
{
var type = this.GetType();
var modelClassProperties = TypeDescriptor
.GetProperties(type)
.Cast();

var errorText =
(from modelProp in modelClassProperties
where modelProp.Name == columnName
from attribute in modelProp.Attributes.OfType()
from displayNameAttribute in modelProp.Attributes.OfType()
where !attribute.IsValid(modelProp.GetValue(this))
select attribute.FormatErrorMessage(displayNameAttribute == null ? modelProp.Name : displayNameAttribute.DisplayName))
.FirstOrDefault();

return errorText;
}
}

protected void NotifyPropertyChanged(string propertyName)
{
if (string.IsNullOrWhiteSpace(propertyName))
{
throw new ArgumentNullException("propertyName");
}

if (!this.GetType().GetProperties().Any(x => x.Name == propertyName))
{
throw new ArgumentException(
"The property name does not exist in this type.",
"propertyName");
}

var handler = this.PropertyChanged;
if (handler != null)
{
if (this.Context != null)
{
this.Context.Post(obj => handler(this, new PropertyChangedEventArgs(propertyName)), null);
}
else
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

用法示例:

public class LogOnViewModel : ViewModelBase
{
[DisplayName("User Name")]
[Required]
[MailAddress] // This is a custom DataAnnotation I wrote
public string UserName
{
get
{
return this.userName;
}
set
{
this.userName = value;
this.NotifyPropertyChanged("UserName");
}
}

[DisplayName("Password")]
[Required]
public string Password
{
get; // etc
set; // etc
}
}

利用 IDataErrorInfo 进行一次性验证例程

老实说,我最终同时使用了注解和开关。我将注释用于简单验证,如果我有更复杂的验证(例如“仅在设置了其他属性时才验证此属性”),那么我将求助于 this[ 的覆盖中的开关] 索引。该模式通常看起来像这样(只是一个虚构的例子,它不一定有意义:

public override string this[string columnName]
{
get
{
// Let the base implementation run the DataAnnotations validators
var error = base[columnName];

// If no error reported, run my custom one-off validations for this
// view model here
if (string.IsNullOrWhiteSpace(error))
{
switch (columnName)
{
case "Password":
if (this.Password == "password")
{
error = "See an administrator before you can log in.";
}

break;
}
}

return error;
}

一些看法

至于将属性名称指定为字符串:您可以使用 lambda 做一些奇特的事情,但我的诚实建议是克服它。您可能会注意到,在我的 ViewModelBase 中,我的小 NotifyPropertyChanged 帮助程序执行了一些反射魔法,以确保我没有乱指属性名称——它帮助我检测快速处理数据绑定(bind)错误,而不是跑来跑去 20 分钟才弄清楚我错过了什么。

您的应用程序将进行一系列验证,从 UI 属性级别的“必需”或“最大长度”等琐碎的事情到不同 UI 级别的“仅当检查其他内容时才需要”以及所有在域/持久性级别中达到“用户名不存在”的方式。您会发现,您将不得不在 UI 中重复一些验证逻辑与在域中添加大量元数据以向 UI 描述自身之间做出权衡,并且您必须权衡这些向用户显示不同类别的验证错误。

希望对您有所帮助。祝你好运!

关于C# 验证 : IDataErrorInfo without hard-coded strings of property name?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4383754/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com