使用 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; }