[英]Unity - Resolve generic implementation that inherits from T
I'm using Unity and want to resolve all implementations which have a generic type that is assignable from a specific type. 我正在使用Unity并希望解决所有具有可从特定类型分配的泛型类型的实现。
I currently do the registrations like this: 我目前正在进行如下注册:
container.RegisterType<IQueryGenerator<IPerson>, PersonQueryGenerator>("1");
container.RegisterType<IQueryGenerator<ICustomer>, CustomerQueryGenerator>("2");
container.RegisterType<IQueryGenerator<IEmployee>, EmployeeQueryGenerator>("3");
container.RegisterType<IQueryGenerator<IManager>, ManagerQueryGenerator>("4");
Then the hierarchy goes like this: 层次结构如下:
public interface IPerson
{
}
public interface ICustomer : IPerson
{
}
public interface IEmployee : IPerson
{
}
public interface IManager : IEmployee
{
}
And the interface of the implementations that I'm trying to resolve: 以及我正在尝试解决的实现的接口:
public interface IQueryGenerator<T>
{
IEnumerable<Expression<Func<T, bool>>> GenerateQueries();
}
Now I want to be able to resolve all IQueryGenerators where the generic type is assignable to the type I have. 现在我希望能够解析所有IQueryGenerators,其泛型类型可分配给我的类型。 So I have a factory which is supposed to wrap it: 所以我有一个应该包装它的工厂:
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();
}
}
}
What I want is that _container.ResolveAll<IQueryGenerator<IEmployee>>()
returns PersonQueryGenerator
, EmployeeQueryGenerator
and ManagerQueryGenerator
because IManager
is an IEmployee
and IEmployee
is a IPerson
. 我想要的是_container.ResolveAll<IQueryGenerator<IEmployee>>()
返回PersonQueryGenerator
, EmployeeQueryGenerator
和ManagerQueryGenerator
因为IManager
是一个IEmployee
而IEmployee
是一个IPerson
。
_container.ResolveAll<IQueryGenerator<ICustomer>>()
returns PersonQueryGenerator
, and CustomerQueryGenerator
. _container.ResolveAll<IQueryGenerator<ICustomer>>()
返回PersonQueryGenerator
和CustomerQueryGenerator
。
IEmployee
can be casted down to IPerson
, which can be handled by PersonQueryGenerator
. IEmployee
可以转换为IPerson
,可以由PersonQueryGenerator
处理。
How do I register the IQueryGenerators, and how do I resolve them based on TModel
? 如何注册IQueryGenerators,以及如何基于TModel
解决它们? Or is there any other way to retrieve the QueryGenerators based upon the interfaces TModel
implement? 或者有没有其他方法可以根据TModel
实现的接口检索QueryGenerators?
EDIT: 编辑:
I've added a proof-of-concept of what I want to do. 我添加了一个我想做的概念验证。 It works well, but is very hard-coded. 它运作良好,但非常硬编码。
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; }
}
Output is: 输出是:
PersonQueryGenerator called
EmployeeGenerator called
ManagerQueryGenerator called
Manager: Executive Manager
This is what I want, but with a more generic type management and I really would like to use Expression<Func<T,bool>>
because it will be used with EF. 这就是我想要的,但是使用更通用的类型管理,我真的想使用Expression<Func<T,bool>>
因为它将与EF一起使用。
public interface IQueryGenerator<T>
{
IEnumerable<Expression<Func<T, bool>>> GenerateQueries();
}
Instead of: 代替:
public interface IQueryGenerator<in T>
{
IEnumerable<Func<T, bool>> GenerateQueries();
}
It is possible with little bit reflection when you're filling the unity container. 当您填充统一容器时,可能会有一点点反射。
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;
}
Example: 例:
static void Main(string[] args)
{
RegisterGenerator<IPerson, PersonQueryGenerator>();
RegisterGenerator<IManager, ManagerQueryGenerator>();
var managers = new List<IPerson>
{
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
}
}.AsEnumerable();
var queries = GenerateQueries<IPerson>();
managers = queries.Aggregate(managers, (current, expression) => current.Where(expression));
foreach (var manager in managers)
{
Console.WriteLine("Manager: {0}", manager.Name);
}
Console.ReadKey();
}
using System;
using System.Collections.Generic;
using System.Linq;
using Unity;
namespace ConsoleApplication1
{
internal class Program
{
private static UnityContainer container = new UnityContainer();
private static void Main(string[] args)
{
container.RegisterType<Manager>(new ContainerControlledLifetimeManager());
container.RegisterType<IPerson, Manager>();
container.RegisterType<IEmployee, Manager>();
container.RegisterType<IManager, Manager>();
container.RegisterType<IQueryGenerator<IPerson>, PersonQueryGenerator>();
container.RegisterType<IQueryGenerator<IEmployee>, EmployeeGenerator>();
container.RegisterType<IQueryGenerator<IManager>, ManagerQueryGenerator>();
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
},
};
// Fetch queries and return them.
var queries = new List<Func<IManager, bool>>();
queries.AddRange(GenerateQueries<IPerson>());
queries.AddRange(GenerateQueries<IEmployee>());
queries.AddRange(GenerateQueries<IManager>());
managers = queries.Aggregate(managers, (current, expression) => current.Where(expression));
foreach (var manager in managers)
{
Console.WriteLine("Manager: {0}", manager.Name);
}
Console.ReadKey();
}
// I want to use this method instead.
private static IEnumerable<Func<TModel, bool>> GenerateQueries<TModel>()
{
var queryGenerator = container.Resolve<IQueryGenerator<TModel>>();
return queryGenerator.GenerateQueries();
}
}
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; }
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.