用适当的具体类型创建泛型类的实例

时间:2019-05-13 10:14:02

标签: c# generics service-locator

我想在EF验证框架之上实现通用实体验证机制。我所做的是使用单个UPDATE public."mytable" SET alias='{a, b}' WHERE id='myid' 方法创建了一个通用接口,该接口将由不同的实体验证器实现。然后,我使用服务定位器模式实例化EF ofd.Filter = "CSV files (*.csv)|*.csv"; 方法重写内的相关具体验证器实现。这是我的实现:

Validator界面

Validate()

验证器实施

ValidateEntity

服务定位器(验证定位器)

public interface IEntityValidator<T>
{
    DbEntityValidationResult ValidateEntity(T entity);
}

ClientContext中的ValidateEntity内部方法

public class BranchValidator<Branch>: IEntityValidator<Branch>
{
    ClientContext clientContext;

    public BranchValidator(ClientContext clientContext)
    {
        this.clientContext = clientContext;
    }

    public DbEntityValidationResult ValidateEntity(Branch entity)
    {
        throw new NotImplementedException();
    }
}

我在public static class ValidatorLocator<T> { public static IEntityValidator<T> validatorObject; public static IEntityValidator<T> GetValidator(string entityType, ClientContext clientContext) { switch (entityType) { case "User": validatorObject = new UserValidator<T>(clientContext); break; case "Branch": validatorObject = new BranchValidator<T>(clientContext); break; default: validatorObject = null; break; } return validatorObject; } public static void Validate(T obj) { validatorObject.ValidateEntity(obj); } } 方法中遇到编译器错误-在下一行:

public partial class ClientContext : DbContext
{
    public ClientContext(string connectionString)
        : base(connectionString)
    {
    }

    protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
    {
        var entityName = entityEntry.Entity.GetType().FullName; 

        IEntityValidator<T> validatorObj = (T)ValidatorLocator.GetValidator(entityName, this);


        return base.ValidateEntity(entityEntry, items);
    }
}

错误提示:使用通用类型'ValidatorLocator'需要1个类型参数

返回我的泛型类型的具体实例的正确方法是什么?

1 个答案:

答案 0 :(得分:0)

您可以使用诸如依赖项注入容器之类的东西:

public class ClientContext { }

public interface IEntityValidator<T> { }

public class Branch { }
public class BranchValidator : IEntityValidator<Branch>
{
    public BranchValidator(ClientContext clientContext)
    {
        Console.WriteLine("Creating a BranchValidator with context {0}", clientContext);
    }
}

public class Other { }
public class OtherValidator : IEntityValidator<Other> { }

public static class ValidatorLocator
{
    private static readonly Dictionary<Type, Type> ValidatorContainer
        = new Dictionary<Type, Type>();

    /// <summary>
    /// Use this method to register the validator class for an entity type.
    /// It should have a constructor with ClientContext parameter
    /// </summary>
    public static void RegisterValidator<TEntity,TEntityValidator>()
        where TEntityValidator : IEntityValidator<TEntity>
    {
        Console.WriteLine("=== RegisterValidator ===");
        Console.WriteLine("Registering {0} to validate {1}:", 
            typeof(TEntityValidator), typeof(TEntity));
        ValidatorContainer.Add(typeof(TEntity), typeof(TEntityValidator));
        Console.WriteLine("  Checking constructor with ClientContext parameter"); 
        var ctorParamTypes = new[] {typeof(ClientContext)};
        var validatorCtor = typeof(TEntityValidator).GetConstructor(ctorParamTypes);
        if (validatorCtor == null)
            Console.WriteLine("  Couldn't find the constructor!!");
        else
            Console.WriteLine("  Successfully registered!");
    }

    public static IEntityValidator<TEntity> GetValidator<TEntity>(ClientContext clientContext)
    {
        Console.WriteLine("=== GetValidator ===");
        Console.WriteLine("Getting validator for {0}", typeof(TEntity));
        var validatorType = ValidatorContainer[typeof(TEntity)];
        Console.WriteLine("  Looking for the constructor");
        var ctorParamTypes = new[] {typeof(ClientContext)};
        var validatorCtor = validatorType.GetConstructor(ctorParamTypes);
        Console.WriteLine("  Constructor found");
        var ctorParams = new[] {clientContext};
        Console.WriteLine("  Creating validator");
        var validator = validatorCtor.Invoke(ctorParams);
        Console.WriteLine("  Succesfully created");
        return (IEntityValidator<TEntity>)validator;
    }
}

要使用它,必须为每种实体类型注册验证器类,然后才能找到服务构造函数并调用它。此技术有多种变体:例如,您可以注册每个验证器的单例实例并重用它,而不用寻找构造函数并在每次使用时调用它。

注意:很显然,Console.WriteLine在这里可以查看正在发生的事情,但在实际实现中不是必需的

用法示例:

class Program
{
    static void Main(string[] args)
    {
        ValidatorLocator.RegisterValidator<Branch,BranchValidator>();
        ValidatorLocator.RegisterValidator<Other,OtherValidator>();

        var clientContex = new ClientContext();
        ValidatorLocator.GetValidator<Branch>(clientContext);

        Console.WriteLine("Press a key to exit!!");
        Console.ReadKey();
    }
}