如何将所有与特定C#接口匹配的类型放在IDictionary中?

时间:2010-05-19 16:15:34

标签: c# generics reflection interface

我在同一个界面中有许多类,都在同一个程序集中,都符合相同的通用接口:

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}}接口做到这一点。

4 个答案:

答案 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);