.NET泛型类型 - 查找最具体的类型

时间:2009-10-19 19:08:29

标签: c# .net generics reflection

是否有任何好的算法可用于确定实例化的“最佳”类型以满足请求?

例如说我有以下课程:

public interface ISometype<T> {}
public class SomeTypeImpl<T>:ISometype<T> {}
public class SomeSpecificTypeImpl<T>:ISometype<T> where T: ISpecificSpecifier {}
public interface ISpecificSpecifier { } 

假设调用者想要此接口的最佳实现类型。我可以像这样实现这个特定的方法:

public Type GetBestImplementationType(Type genericParam) {
    try {
        return typeof(SomeSpecificTypeImpl<>).MakeGenericType(genericParam);
    } catch(ArgumentException) {}
    return typeof(SomeTypeImpl<>).MakeGenericType(genericParam);
}

虽然此实现适用于此特定情况,但我更关注可能存在多个潜在特定实现和多个通用参数的概括:

public Type GetBestImplementationType(Type[] genericParams, Type[] potentialTypes) {
    foreach(var t in potentialTypes) {
        try {
            return t.MakeGenericType(genericParams);
        } catch(ArgumentException) {}
    }
    throw new Exception("unable to find specific implementation type");
}

这应该可行,因为potentialTypes数组是从大多数到最不特定的顺序提供的。因此,对于答案,要么实现此方法的算法(或类似的东西),要么实现我可以在此方法中使用的排序的算法。 [警告:代码未经测试,可能存在语法/逻辑错误]

2 个答案:

答案 0 :(得分:0)

我认为唯一的方法是迭代所有程序集中所有可能非常慢的类。

以下是asp.net MVC如何搜索项目中的所有控制器:

    private static List<Type> GetAllControllerTypes(IBuildManager buildManager) {
        // Go through all assemblies referenced by the application and search for
        // controllers and controller factories.
        List<Type> controllerTypes = new List<Type>();
        ICollection assemblies = buildManager.GetReferencedAssemblies();
        foreach (Assembly assembly in assemblies) {
            Type[] typesInAsm;
            try {
                typesInAsm = assembly.GetTypes();
            }
            catch (ReflectionTypeLoadException ex) {
                typesInAsm = ex.Types;
            }
            controllerTypes.AddRange(typesInAsm.Where(IsControllerType));
        }
        return controllerTypes;
    }

在您的情况下,您可以将代码重写为类似的内容:

    private static List<Type> GetAllSubtypesOf(Type anInterface) {
        List<Type> types = new List<Type>();
        ICollection assemblies = buildManager.GetReferencedAssemblies();
        foreach (Assembly assembly in assemblies) {
            Type[] typesInAsm;
            try {
                typesInAsm = assembly.GetTypes();
            }
            catch (ReflectionTypeLoadException ex) {
                typesInAsm = ex.Types;
            }
            types.AddRange(typesInAsm.Where(t => anInterface.IsAssignableFrom(t)));
        }
        return types;
    }

请注意,因为迭代所有程序集是非常低效的asp.net MVC做一次并缓存结果。

答案 1 :(得分:0)

似乎:

  1. 没有更好的方法来确定是否满足泛型类型的约束,而不是尝试创建类型并捕获异常(可以这样做,但似乎至少与异常方法一样长,并且远远不够更复杂)。
  2. 由于#1,[从计算上]很难从一个类型到最不具体地排序一组类型。相反,在代码中,我的解决方案是明确地告诉我的容器如何订购类型。