我在同一个界面中有许多类,都在同一个程序集中,都符合相同的通用接口:
public class AppleFactory : IFactory<Apple> { ... }
public class BananaFactory : IFactory<Banana> { ... }
// ...
可以安全地假设,如果某个特定IFactory<T>
有T
,那么它就是唯一的IFactory<Apple>
。 (也就是说,没有两件事可以实现typeof(T)
。)
我想使用反射来获取所有这些类型,然后将它们全部存储在IDictionary中,其中键为IFactory<T>
,值为相应的_map = new Dictionary<Type, object>();
foreach(Type t in [...]) {
object factoryForType = System.Reflection.[???](t);
_map[t] = factoryForType;
}
。我想最终我们会结束这样的事情:
System.Reflection
最好的方法是什么?我很难看到我如何使用{{1}}接口做到这一点。
答案 0 :(得分:2)
为了识别作为接口通用定义的类,我使用以下扩展方法:
public static class TypeExtensions
{
public static bool IsGenericTypeOf(this Type t, Type genericDefinition)
{
return t.IsGenericType && genericDefinition.IsGenericType && t.GetGenericTypeDefinition() == genericDefinition.GetGenericTypeDefinition();
}
}
然后你可以使用Type.GetGenericArguments方法找到“T”。
这样你就会得到类似的东西:
var allTypes = ...; // Maybe: Assembly.GetExecutingAssembly().GetTypes()
var dictionary = allTypes.Where(t => t.IsGenericTypeOf(typeof(IFactory<>))).ToDictionary(t => t.GetGenericArguments()[0], t => t);
答案 1 :(得分:1)
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
bool isIFactory = (from i in type.GetInterfaces()
where i.IsGenericType &&
i.GetGenericTypeDefinition() == typeof(IFactory<>) &&
i.IsAssignableFrom(i.GetGenericArguments()[0])
// this one could be also changed to i.GetGenericArguments()[0] == type
// however, it'll generate an anonymous class, which will show in the outer foreach
select i).Count() == 1;
}
答案 2 :(得分:1)
private readonly Dictionary<Type, object> _map = Assembly.GetExecutingAssembly()
.GetTypes()
.SelectMany(t => t.GetInterfaces()
.Where(i => i.IsGenericType
&& (i.GetGenericTypeDefinition() == typeof(IFactory<>))
&& !i.ContainsGenericParameters),
(t, i) => new
{
KeyType = i.GetGenericArguments()[0],
Factory = Activator.CreateInstance(t)
})
.ToDictionary(x => x.KeyType, x => x.Factory);
// ...
public IFactory<T> GetFactory<T>()
{
object factory;
if (_map.TryGetValue(typeof(T), out factory))
return (IFactory<T>)factory;
// no factory found so return null (or throw an exception if you prefer)
return null;
}
答案 3 :(得分:0)
问题在于匹配所有IFactory,因为你必须指定T.最简单的解决方案是创建另一个接口IFactory
并使IFactory<T>
成为它的通用版本。然后你可以匹配所有的IFactory然后构建字典。
Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t is IFactory)
.ToDictionary(k => k.GetGenericArguments()[0],v => v);