加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – Unity – 解析从T继承的泛型实现

发布时间:2020-12-15 20:58:32 所属栏目:百科 来源:网络整理
导读:我正在使用Unity并希望解决所有具有可从特定类型分配的泛型类型的实现. 我目前正在进行如下注册: container.RegisterTypeIQueryGeneratorIPerson,PersonQueryGenerator("1");container.RegisterTypeIQueryGeneratorICustomer,CustomerQueryGenerator("2");c
我正在使用Unity并希望解决所有具有可从特定类型分配的泛型类型的实现.

我目前正在进行如下注册:

container.RegisterType<IQueryGenerator<IPerson>,PersonQueryGenerator>("1");
container.RegisterType<IQueryGenerator<ICustomer>,CustomerQueryGenerator>("2");
container.RegisterType<IQueryGenerator<IEmployee>,EmployeeQueryGenerator>("3");
container.RegisterType<IQueryGenerator<IManager>,ManagerQueryGenerator>("4");

层次结构如下:

public interface IPerson
{
}

public interface ICustomer : IPerson
{
}

public interface IEmployee : IPerson
{
}

public interface IManager : IEmployee
{
}

以及我正在尝试解决的实现的接口:

public interface IQueryGenerator<T>
{
   IEnumerable<Expression<Func<T,bool>>>  GenerateQueries();
}

现在我希望能够解析所有IQueryGenerators,其泛型类型可分配给我的类型.所以我有一个应该包装它的工厂:

public class QueryFactory
    {
        private readonly IUnityContainer _container;

        public QueryFactory(IUnityContainer container)
        {
            _container = container;
        }

        public IEnumerable<Expression<Func<TModel,bool>>> GenerateQueries<TModel>()
        {
            // Get all querygenerators which can handle TModel.
            IQueryGenerator<TModel>[] queryGenerators = _container.ResolveAll<IQueryGenerator<TModel>>();
            foreach (var queryGenerator in queryGenerators)
            {
                // Do something with queryGenerator.
                var result = queryGenerator.GenerateQueries();
            }
        }
    }

我想要的是_container.ResolveAll< IQueryGenerator< IEmployee>>()返回PersonQueryGenerator,EmployeeQueryGenerator和ManagerQueryGenerator,因为IManager是IEmployee而IEmployee是IPerson.

_container.ResolveAll< IQueryGenerator< ICustomer>>()返回PersonQueryGenerator和CustomerQueryGenerator.

IEmployee可以转换为IPerson,可以由PersonQueryGenerator处理.

如何注册IQueryGenerators,以及如何基于TModel解决它们?或者有没有其他方法可以根据TModel实现的接口检索QueryGenerators?

编辑:

我添加了一个我想做的概念验证.它运作良好,但非常硬编码.

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<IManager> managers = new List<IManager>
        {
            new Manager()
            {
                Birthday = DateTime.Now.AddDays(1),Name = "Executive Manager",EmployeeNumber = 9,IsExecutive = true,Salary = 1000
            },new Manager()
            {
                Birthday = DateTime.Now.AddDays(-1),Name = "Ordinary Manager",EmployeeNumber = 8,IsExecutive = false,Salary = 900
            },};
        var queries = GenerateQueries();

        managers = queries.Aggregate(managers,(current,expression) => current.Where(expression));
        foreach (var manager in managers)
        {
            Console.WriteLine("Manager: {0}",manager.Name);
        }
        Console.ReadKey();
    }

    // Change this to a generic method.
    static IEnumerable<Func<IManager,bool>> GenerateQueries()
    {
        // Change this to a more generic management
        IList<IQueryGenerator<IManager>> queryGenerators = new List<IQueryGenerator<IManager>>();
        if (typeof(IPerson).IsAssignableFrom(typeof(IManager)))
        {
            queryGenerators.Add(new PersonQueryGenerator());
        }
        if (typeof(IEmployee).IsAssignableFrom(typeof(IManager)))
        {
            queryGenerators.Add(new EmployeeGenerator());
        }
        if (typeof(IManager).IsAssignableFrom(typeof(IManager)))
        {
            queryGenerators.Add(new ManagerQueryGenerator());
        }

        // Fetch queries and return them.
        var queries = new List<Func<IManager,bool>>();
        foreach (var queryGenerator in queryGenerators)
        {
            // Do something with queryGenerator.
            queries.AddRange(queryGenerator.GenerateQueries());
        }
        return queries;
    }

    // I want to use this method instead.
    static IEnumerable<Func<TModel,bool>> GenerateQueries<TModel>()
    {
        // Do the same thing as the method above
        //TODO: Resolve all IQueryGenerators that can handle TModel.
        return null;
    }
}

public interface IQueryGenerator<in T>
{
    IEnumerable<Func<T,bool>> GenerateQueries();
}

public class ManagerQueryGenerator : IQueryGenerator<IManager>
{
    public IEnumerable<Func<IManager,bool>> GenerateQueries()
    {
        Console.WriteLine("ManagerQueryGenerator called");
        yield return x => x.IsExecutive;
    }
}

public class PersonQueryGenerator : IQueryGenerator<IPerson>
{
    public IEnumerable<Func<IPerson,bool>> GenerateQueries()
    {
        Console.WriteLine("PersonQueryGenerator called");
        yield return x => x.Birthday > DateTime.Now;
    }
}

public class EmployeeGenerator : IQueryGenerator<IEmployee>
{
    public IEnumerable<Func<IEmployee,bool>> GenerateQueries()
    {
        Console.WriteLine("EmployeeGenerator called");
        yield return x => x.Salary > 900;
    }
}

public interface IHaveName
{
    string Name { get; set; }
}

public interface IPerson : IHaveName
{
    DateTime Birthday { get; set; }
}

public interface ICustomer : IPerson
{
    int MoneyToSpend { get; set; }
}

public interface IEmployee : IPerson
{
    int EmployeeNumber { get; set; }
    int Salary { get; set; }
}

public interface IManager : IEmployee
{
    bool IsExecutive { get; set; }
}

public class Manager : IManager
{
    public string Name { get; set; }
    public DateTime Birthday { get; set; }
    public int EmployeeNumber { get; set; }
    public int Salary { get; set; }
    public bool IsExecutive { get; set; }
}

输出是:

PersonQueryGenerator called
EmployeeGenerator called
ManagerQueryGenerator called
Manager: Executive Manager

这就是我想要的,但是使用更通用的类型管理,我真的想使用Expression< Func< T,bool>>因为它将与EF一起使用.

public interface IQueryGenerator<T>
{
   IEnumerable<Expression<Func<T,bool>>>  GenerateQueries();
}

代替:

public interface IQueryGenerator<in T>
{
   IEnumerable<Func<T,bool>>  GenerateQueries();
}

解决方法

当您填充统一容器时,可能会有一点点反射.

private static UnityContainer container = new UnityContainer();

static void RegisterGenerator<T,TG>() where TG : IQueryGenerator<T>
{
  var assembly = typeof(T).Assembly;
  // walk trough all interfaces in assembly,if the interface inherits from
  // typeof(T),add that particular IQueryGenerator<> to container as well
  foreach (var type in assembly.GetTypes())
  {
    if (typeof(T).IsAssignableFrom(type) && type.IsInterface)
    {
      var generatorType = typeof(IQueryGenerator<>).MakeGenericType(type);
      container.RegisterType(generatorType,typeof(TG),type.Name);
    }
  }
}

static IEnumerable<Func<T,bool>> GenerateQueries<T>() where T : IPerson
{
  var queryGenerators = container.ResolveAll<IQueryGenerator<T>>().ToList();

  // Fetch queries and return them.
  var queries = new List<Func<T,bool>>();
  foreach (var queryGenerator in queryGenerators)
  {
    // Do something with queryGenerator.
    queries.AddRange(queryGenerator.GenerateQueries());
  }
  return queries;
}

例:

static void Main(string[] args)
{
  RegisterGenerator<IPerson,PersonQueryGenerator>();
  RegisterGenerator<IManager,ManagerQueryGenerator>();

  var managers = new List<IPerson>
  {
    new Manager
    {
      Birthday = DateTime.Now.AddDays(1),Salary = 1000
    },new Manager
    {
      Birthday = DateTime.Now.AddDays(-1),Salary = 900
    }
  }.AsEnumerable();
  var queries = GenerateQueries<IPerson>();

  managers = queries.Aggregate(managers,expression) => current.Where(expression));
  foreach (var manager in managers)
  {
    Console.WriteLine("Manager: {0}",manager.Name);
  }
  Console.ReadKey();
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读