控制台环境中的 C# 自定义属性验证



我的问题是关于在 C# 中使用自定义属性进行验证。

我不太明白验证是如何工作的。我已经声明了一个带有验证规则的属性,但是当应该抛出错误时,它不是。

属性:

[AttributeUsage(AttributeTargets.Property)]
public class NotNullAttribute : Attribute
{
public bool IsValid(object value)
{
if (value is string && (string)value != "")
{
return false;
}
return true;
}
}

在属性中,我检查属性是否为字符串类型,以及其值是否为空字符串,因为这是我必须检查的。

任务是检查属性是否为string,如果它是空字符串,则它无效,否则无效。

我的Person课:

class Person
{
[NotNull]
public string Name { get; set; }
}

在这里,我正在应用自定义属性。

主要方法:

class Program
{
static void Main(string[] args)
{
Person p1 = new Person();
p1.Name = "";
Console.WriteLine("Validation done");
Console.ReadKey();
}
}

这是我实例化Person类并将空字符串分配给Name属性的地方。我想这就是应该抛出错误的地方。

所以我的问题是为什么不应用验证?我应该以某种方式从它自己的属性调用IsValid方法吗?

我会对此进行一些解释,提前谢谢!

属性本身只是属性的"装饰器"。如果没有调用它,它将不会自动执行或使用。

但是,在您的情况下,当您可以使用属性本身时,我看不出使用属性的意义:

private string _name = "";
public string Name
{
get
{
return _name;
}
set
{
if ( string.IsNullOrEmpty(value) )
{
//throw or fallback
}
else
{
_name = value;
}
}
}

执行基本值验证正是作业属性资源库的出色选择。例如,如果有人使用无效值,您可以引发异常或设置回退值。

如果您仍然更喜欢使用属性,则仍然需要一些执行验证本身的代码。而且,任何人都可以为属性分配任何有效值,除非执行验证。

例如 ASP.NET MVC 在模型绑定期间使用属性验证 - 它会检查绑定模型类上的验证属性,并在操作方法开始执行之前对其进行验证。

属性验证示例

下面是一个如何使代码与反射一起使用的简单示例。

首先是验证属性的略微更新版本:

[AttributeUsage(AttributeTargets.Property)]
public class NotNullAttribute : Attribute
{
public bool IsValid(object value)
{
if (!string.IsNullOrEmpty(value as string))
{
return false;
}
return true;
}
}

您的代码实际上只允许null""值,我想这与您想要的相反。仅当字符串不null且不为空时,此版本才有效。

现在在Program类中创建一个Validate方法:

private static bool Validate(object model)
{
foreach (var propertyInfo in model.GetType().GetProperties())
{                
foreach (var attribute in propertyInfo.GetCustomAttributes(true))
{
var notNullAttribute = attribute as NotNullAttribute;
if (notNullAttribute != null)
{
if (!notNullAttribute.IsValid(propertyInfo.GetValue(model)))
{
return false;
}
}
}
}
return true;
}

这基本上收集传入参数类型的所有属性,检查属性的所有属性NotNullAttribute然后针对model中的当前值执行属性的IsValid方法。

最后,这是您可以从Main调用它的方法:

static void Main(string[] args)
{
Person p1 = new Person();
p1.Name = "d";
if (Validate(p1))
{
Console.WriteLine("Valid");
}
else
{
Console.WriteLine("Invalid");
}
Console.WriteLine("Validation done");
Console.ReadKey();
}

现在,如果您计划添加更多验证属性,我将首先创建一个接口:

public interface IValidationAttribute
{
bool IsValid(object value);
}

然后从IValidationAttribute派生所有验证属性,并在Validate方法中使用IValidationAttribute代替NotNullAttribute。这样,代码变得更加面向未来,因为您可以随时针对接口进行编程并添加新的验证属性。

public class BankAccount  
{  
public enum AccountType  
{  
Saving,  
Current  
}  
[Required(ErrorMessage="First Name Required")]  
[MaxLength(15,ErrorMessage="First Name should not more than 1`5 character")]  
[MinLength(3,ErrorMessage="First Name should be more than 3 character")]  
public string AccountHolderFirstName { get; set; }  
[Required(ErrorMessage="Last Name Required")]  
[MaxLength(15,ErrorMessage="Last Name should not more than 1`5 character")]  
[MinLength(3,ErrorMessage="Last Name should be more than 3 character")]  
public string AccountHolderLastName { get; set; }  
[Required]  
[RegularExpression("^[0-9]+$", ErrorMessage = "Only Number allowed in AccountNumber")]  
public string AccountNumber { get; set; }  
public AccountType AcType { get; set; }  
[AccountBalaceCheckAttribute]  
public double AccountBalance { get; set; }  
}  

如何验证

public class GenericValidator   
{  
public static bool TryValidate(object obj, out ICollection<ValidationResult> results)  
{  
var context = new ValidationContext(obj, serviceProvider: null, items: null);  
results = new List<ValidationResult>();  
return Validator.TryValidateObject(  
obj, context, results,  
validateAllProperties: true  
);  
}  
}

static void Main(string[] args)  
{  
var bankAccount = new BankAccount();  
ICollection<ValidationResult> lstvalidationResult;  
bool valid = GenericValidator.TryValidate(bankAccount, out lstvalidationResult);  
if (!valid)  
{  
foreach (ValidationResult res in lstvalidationResult)  
{  
Console.WriteLine(res.MemberNames +":"+ res.ErrorMessage);  
}  
}  
Console.ReadLine();  
}  

最新更新