使用 Fluent Validation 和 Entity Framework Core - Base Class 中的类型问题构建通用验证器
Constructing A Generic Validator using Fluent Validation and Entity Framework Core - Type Problems in Base Class
我能够使用带有 Fluent 验证的 EF Core 属性来验证最大字段长度:
我正在尝试通过为我的所有模型创建基本验证 class 来扩展它。我在实例化基础 class 时遇到运行时错误。我不确定如何让基础 class 知道我正在使用什么类型 class。
这是我创建的class:
public abstract class BaseValidator<T> : AbstractValidator<T>
{
public object BaseObject {get;set;}
public BaseValidator()
{
DbContext dbContext = new DataContext();
Microsoft.EntityFrameworkCore.Metadata.IEntityType et = dbContext.Model.FindEntityType(typeof(T));
foreach (var fieldProperty in et.GetProperties())
{
var maxLength = fieldProperty.GetMaxLength();
if (maxLength.HasValue)
{
var parameter = Expression.Parameter(baseObject.GetType()); <<<<<===== RUNTIME ERROR BaseValidator<T>.BaseObject.get returned null.
var memberExpression = Expression.Property(parameter, fieldProperty.Name);
var lambdaExpression = Expression.Lambda<Func<T, string>>(memberExpression, parameter);
RuleFor(lambdaExpression)
.MaximumLength(maxLength.Value);
}
}
}
实现如下:
public class AddressValidator : BaseValidator<Address>
{
public object BaseObject = typeof(Address);
public AddressValidator()
{
如果能帮助我完成这项工作,我将不胜感激。
在BaseValidator<T>
中,这一行:
public object BaseObject {get;set;}
它声明了一个 BaseObject
属性。当 AddressValidator
继承 class 并包含此行时:
public object BaseObject = typeof(Address);
它声明了一个 字段,它是 class 的新字段,并且与 BaseValidator<T>
中声明的同名 属性 完全不同。
您会发现一个旨在引起您注意的警告:
'AddressValidator.BaseObject' hides inherited member 'BaseValidator<Address>.BaseObject'. Use the new keyword if hiding was intended.
您正在将 typeof(Address)
分配给该字段,但回到基础 class,它没有字段的概念或分配给它的值。隐藏似乎不是预期的,因此您可以将其删除。
现在,BaseValidator<T>.BaseObject
是您剩下的唯一一个(也是构造函数见过的唯一一个)。但是,它从来没有被赋值,所以当构造函数试图获取它的值时,它只能是null
。那当然意味着你得到 NullReferenceException
.
根据您正在构建的表达式,您希望参数是实体类型,您可以方便地在类型参数中使用该实体类型 T
。在那里使用 typeof(T)
:
var parameter = Expression.Parameter(typeof(T));
当 AddressValidator
派生自 BaseBalidator<Address>
.
时,将创建实体类型 Address
的参数表达式
您似乎希望 BaseObject
成为要验证的对象。将其声明为 T
.
类型
public T BaseObject { get; set; }
要在基 class 中分配它,请在 AddressValidator
的构造函数中接受它并将其传递给基 class 的构造函数。
public class AddressValidator : BaseValidator<Address>
{
public AddressValidator(Address baseObject)
: base(baseObject)
{
}
}
public abstract class BaseValidator<T> : AbstractValidator<T>
{
public BaseValidator(T baseObject)
{
BaseObject = baseObject ?? throw new ArgumentNullException(nameof(baseObject));
//... and then the rest of the constructor as you have it.
}
}
由于构造函数正在分配 BaseObject
并且您可能不需要更改它,因此您可以将其设为只读 属性:
public T BaseObject { get; }
我能够使用带有 Fluent 验证的 EF Core 属性来验证最大字段长度:
我正在尝试通过为我的所有模型创建基本验证 class 来扩展它。我在实例化基础 class 时遇到运行时错误。我不确定如何让基础 class 知道我正在使用什么类型 class。
这是我创建的class:
public abstract class BaseValidator<T> : AbstractValidator<T>
{
public object BaseObject {get;set;}
public BaseValidator()
{
DbContext dbContext = new DataContext();
Microsoft.EntityFrameworkCore.Metadata.IEntityType et = dbContext.Model.FindEntityType(typeof(T));
foreach (var fieldProperty in et.GetProperties())
{
var maxLength = fieldProperty.GetMaxLength();
if (maxLength.HasValue)
{
var parameter = Expression.Parameter(baseObject.GetType()); <<<<<===== RUNTIME ERROR BaseValidator<T>.BaseObject.get returned null.
var memberExpression = Expression.Property(parameter, fieldProperty.Name);
var lambdaExpression = Expression.Lambda<Func<T, string>>(memberExpression, parameter);
RuleFor(lambdaExpression)
.MaximumLength(maxLength.Value);
}
}
}
实现如下:
public class AddressValidator : BaseValidator<Address>
{
public object BaseObject = typeof(Address);
public AddressValidator()
{
如果能帮助我完成这项工作,我将不胜感激。
在BaseValidator<T>
中,这一行:
public object BaseObject {get;set;}
它声明了一个 BaseObject
属性。当 AddressValidator
继承 class 并包含此行时:
public object BaseObject = typeof(Address);
它声明了一个 字段,它是 class 的新字段,并且与 BaseValidator<T>
中声明的同名 属性 完全不同。
您会发现一个旨在引起您注意的警告:
'AddressValidator.BaseObject' hides inherited member 'BaseValidator<Address>.BaseObject'. Use the new keyword if hiding was intended.
您正在将 typeof(Address)
分配给该字段,但回到基础 class,它没有字段的概念或分配给它的值。隐藏似乎不是预期的,因此您可以将其删除。
现在,BaseValidator<T>.BaseObject
是您剩下的唯一一个(也是构造函数见过的唯一一个)。但是,它从来没有被赋值,所以当构造函数试图获取它的值时,它只能是null
。那当然意味着你得到 NullReferenceException
.
根据您正在构建的表达式,您希望参数是实体类型,您可以方便地在类型参数中使用该实体类型 T
。在那里使用 typeof(T)
:
var parameter = Expression.Parameter(typeof(T));
当 AddressValidator
派生自 BaseBalidator<Address>
.
Address
的参数表达式
您似乎希望 BaseObject
成为要验证的对象。将其声明为 T
.
public T BaseObject { get; set; }
要在基 class 中分配它,请在 AddressValidator
的构造函数中接受它并将其传递给基 class 的构造函数。
public class AddressValidator : BaseValidator<Address>
{
public AddressValidator(Address baseObject)
: base(baseObject)
{
}
}
public abstract class BaseValidator<T> : AbstractValidator<T>
{
public BaseValidator(T baseObject)
{
BaseObject = baseObject ?? throw new ArgumentNullException(nameof(baseObject));
//... and then the rest of the constructor as you have it.
}
}
由于构造函数正在分配 BaseObject
并且您可能不需要更改它,因此您可以将其设为只读 属性:
public T BaseObject { get; }