泛型类型继承


public class BaseGenericType<T>
{
}
public class SubGenericType<T>: BaseGenericType<List<T>>
{
}

上面有两个泛型类型,一个继承自另一个,但仍然是泛型。奇怪的是typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<>))返回false。并且typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<List<>>))仍然返回false。我已经尝试过GetGenericTypeDefinition()MakeGenericType()GetGenericArguments()来检查继承,但仍然不起作用。但typeof(SubGenericType<int>).IsSubclassOf(typeof(BaseGenericType<List<int>>))返回true。

我想要的是通过反射获得所有类,然后获取从传入的泛型类型继承的特定类

例如

(1( List<int>-->

(2( 获取泛型类型定义===List<T>-->

(3( 使通用===BaseGenericType<List<T>>-->

(4( 查找子类===SubGenericType<T>

(5( 使通用===SubGenericType<int>

在步骤(4(中,尽管我实际上具有SubGenericType<T>,但我一无所获。为什么?

一旦我写了这个方法来检查泛型类型继承:

    static bool IsSubclassOfOpenGeneric(Type generic, Type toCheck)
    {
        while (toCheck != null && toCheck != typeof(object))
        {
            var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
            if (generic == cur)
            {
                return true;
            }
            toCheck = toCheck.BaseType;
        }
        return false;
    }

返回true:

IsSubclassOfOpenGeneric(typeof(BaseGenericType<>), typeof(SubGenericType<int>))

不过它不检查接口。

顺便说一句,通常如果您有这样的关系,并且您自己编写所有类,可以考虑使用接口。它更容易处理。例如,您可以有一个IGenericType接口,而不带泛型参数。有时你只是不关心泛型类型,只想访问不依赖于泛型类型的成员。有时你只想简单地检查一下是否是其中之一您可以使用类型方差。

最后,我明白了。这正是解决方案。为了详细解释,我必须介绍一些非抽象编码:

这是关于一个价值转换器。我的目的很简单,让用户添加自己的值转换器。在转换步骤中,我将首先检查内置类型的转换器(如IConvertible(,如果找不到,我将先在当前执行的程序集中搜索所有继承我提供的特定abstract类的自定义转换器类。abstract类实现了一个interface,以对以后的反射进行约束。然后,我过滤那些反射的类,寻找匹配的类。

这是基类和接口(全部嵌套(:

    private interface ICustomConverter
    {
        Type SourceType { get; }
        object CallConvert(string input);
    }
    public abstract class CustomConverter<T> : ICustomConverter
    {
        public abstract T Convert(string input);
        public Type SourceType
        {
            get { return typeof (T); }
        }
        object ICustomConverter.CallConvert(string input)
        {
            return Convert(input);
        }
    }

我已经在父类中使接口私有,并显式地实现了它。这样就不会在外部调用方法CallConvert()

泛型参数T是将string值转换为的类型。例如

    public class Int32Converter:CustomConverter<int>
    {
    }

这很容易处理,因为转换目标类型不是泛型的。我所需要做的就是获得实现ICustomConverter的所有类型,并用给定的intCustomConverter<T>生成一个泛型类型,从而生成CustomConverter<int>。然后,我将这些类筛选为从CustomConverter<int>派生的类,在这里我找到了Int32Converter

后来我遇到了这样的情况:

    public class ListConverter<T>:CustomConverter<List<T>>
    {
    }

    public class DictConverter<T,U>:CustomConverter<Dictionary<T,U>>
    {
    }

我用同样的程序来处理它们。但在我创建了一个泛型类型CustomConverter<List<T>>之后,我发现ListConverter<T>不是从CustomConverter<List<T>>派生的,CustomConverter<List<T>>也不能从CCD_ 31(我用CCD_ 32和CCD_。

我想原因是在分配泛型参数之前,泛型类型代表多个类型。这听起来很奇怪,但却是真的编译器不知道CustomConverter<List<T>>ListConverter<T>中的T代表相同的TYPE事实上,我可以像CustomConverter<List<T>>ListConverter<U>一样写它,然后你告诉我它们之间的继承关系。

由于ListConverter<T>DictConverter<T,U>共享同一个根类,所以基类型检查在这里不起作用。这意味着,如果我查找ListConverter<T>,我也将使用基类检查方法(层次循环检查(获得DictConverter<T,U>。所以我仍然需要制作泛型类型,然后检查泛型参数并进行类型比较。

重点是,我需要查找其泛型参数用作其父类泛型参数中泛型参数的特定类。有点扭曲,但现在很清楚了

这是最后的转换解决方案:

    public static object ToObject(Type type, string value)
        {
            if (type == null)
                throw new ArgumentNullException("type");
            if (!typeof (IConvertible).IsAssignableFrom(type))
            {
                if (type.IsGenericType)
                {
                    Type converterType = typeof (CustomConverter<>).MakeGenericType(type);
                    Type genericConverter =
                        typeof (ICustomConverter).Assembly.Types(Flags.Public)
                            .SingleOrDefault(
                                t =>
                                    typeof (ICustomConverter).IsAssignableFrom(t) && t.IsGenericType &&
                                    t.GetGenericArguments().Length == type.GetGenericArguments().Length && !t.IsAbstract &&
                                    t.MakeGenericType(type.GetGenericArguments()).IsSubclassOf(converterType));
                    if (genericConverter != null)
                    {
                        Type customConverter = genericConverter.MakeGenericType(type.GetGenericArguments());
                        object instance = customConverter.CreateInstance();
                        if (instance is ICustomConverter)
                            return ((ICustomConverter) instance).CallConvert(value);
                    }
                }
                else
                {
                    Type converterType = typeof (CustomConverter<>).MakeGenericType(type);
                    Type customConverter =
                        typeof (ICustomConverter).Assembly.Types(Flags.Public)
                            .SingleOrDefault(t => t.IsSubclassOf(converterType));
                    if (customConverter != null)
                    {
                        object instance = customConverter.CreateInstance();
                        if (instance is ICustomConverter)
                            return ((ICustomConverter) instance).CallConvert(value);
                    }
                }
    
    
                throw new ArgumentException("type is not IConvertible and no custom converters found", type.Name());
            }
            TypeConverter converter = TypeDescriptor.GetConverter(type);
            return converter.ConvertFromString(value);
        }

我还检查了GetGenericArguments().Length,以防List<T>Dictionary<TKey,TValue>发生冲突。

注意:使用了一些自定义扩展方法

相关内容

  • 没有找到相关文章