简体   繁体   English

泛型继承

[英]Generic type inheritance

public class BaseGenericType<T>
{
}

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

I have two generic types above, which one inherits from another but is still generic.我上面有两种通用类型,一种是从另一种继承的,但仍然是通用的。 The strange thing I can't figure out is that typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<>)) returns false.我无法弄清楚的奇怪事情是typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<>))返回 false。 And typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<List<>>)) still returns false.typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<List<>>))仍然返回 false。 I've tried GetGenericTypeDefinition() and MakeGenericType() and GetGenericArguments() to check the inheritance, still not working.我已经尝试过GetGenericTypeDefinition()MakeGenericType()GetGenericArguments()来检查继承,但仍然无法正常工作。 But typeof(SubGenericType<int>).IsSubclassOf(typeof(BaseGenericType<List<int>>)) returns true.但是typeof(SubGenericType<int>).IsSubclassOf(typeof(BaseGenericType<List<int>>))返回 true。

What I want is to get all classes by reflection then grab the specific class which inherits from a generic type passed in.我想要的是通过反射获取所有类,然后获取从传入的泛型类型继承的特定类。

eg例如

(1) List<int> --> (1) List<int> -->

(2)get generic type definition ==> List<T> --> (2)获取泛型类型定义==> List<T> -->

(3)make generic ==> BaseGenericType<List<T>> --> (3)make generic ==> BaseGenericType<List<T>> -->

(4)find subclass ==> SubGenericType<T> (4)找到子类==> SubGenericType<T>

(5)make generic ==> SubGenericType<int> (5)make generic ==> SubGenericType<int>

In step (4) I find nothing although I actually have that SubGenericType<T> .在步骤 (4) 中,虽然我实际上拥有该SubGenericType<T> ,但我什么也没找到。 Why is that?这是为什么?

Once I wrote this method to check generic type inheritance:一旦我编写了这个方法来检查泛型类型继承:

    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;
    }

This returns true:这返回真:

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

It doesn't check interfaces though.虽然它不检查接口。

By the way, usually if you have relations like this, and you write all the classes yourself, consider using interfaces .顺便说一句,通常如果您有这样的关系,并且您自己编写所有类,请考虑使用接口 It is much easier to handle.处理起来要容易得多。 You can for instance have a IGenericType interface without generic argument.例如,您可以拥有一个没有泛型参数的IGenericType接口。 Sometome you just do not care about the generic type and just want to access members which do not depend on the generic type.有些人只是不关心泛型类型,只想访问不依赖于泛型类型的成员。 Sometimes you want to simply check if it is one of those.有时您只想检查它是否是其中之一。 And you can use type variance.还可以使用类型差异。

Finally, I figured it out.最后,我想通了。 This is the very solution.这就是解决方案。 To explain in details, I have to introduce some non-abstract coding:为了详细解释,我不得不介绍一些非抽象的编码:

It's about a value converter.这是一个价值转换器。 My purpose is simple, to let users add their own value converters .我的目的很简单,就是让用户添加自己的价值转换器 In the conversion step, I will check built-in types' converters first(as IConvertible ), if not found, I'll first search the current executing assembly for all custom converter classes that inherit a specific abstract class provided by me.在转换步骤中,我将首先检查内置类型的转换器(如IConvertible ),如果没有找到,我将首先搜索当前执行程序集以查找所有继承我提供的特定abstract类的自定义转换器类。 And an interface is implemented by that abstract class to make constraint for later reflection.并且该abstract类实现了一个interface ,以便为以后的反射做出约束。 Then I filter those reflected classes for the one that matches.然后我过滤那些反射的类以获得匹配的类。

Here is the base class and interface(all nested):这是基类和接口(全部嵌套):

    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);
        }
    }

I've made the interface private in the parent class and implemented explicitly.我在父类中将接口设为私有并显式实现。 So that the method CallConvert() won't be called outside.这样CallConvert()方法就不会被外部调用。

The generic parameter T is the Type to convert the string value to.泛型参数T是要将string值转换为的类型。 eg例如

    public class Int32Converter:CustomConverter<int>
    {
    }

This is easy to handle since the conversion target type isn't generic.这很容易处理,因为转换目标类型不是通用的。 all I need to do is to get all types that implement ICustomConverter , and make a generic type from CustomConverter<T> with the given int , thus CustomConverter<int> .我需要做的就是获取所有实现ICustomConverter类型,并从CustomConverter<T>使用给定的int创建一个泛型类型,即CustomConverter<int> Then I filter those classes for the one that derives from CustomConverter<int> , and here I found Int32Converter .然后我过滤那些派生自CustomConverter<int> ,在这里我找到了Int32Converter

Later I came across this situation:后来我遇到了这样的情况:

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

and

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

I used the same process to deal with them.我使用相同的过程来处理它们。 But after I made a generic type CustomConverter<List<T>> , I found that ListConverter<T> does not derive from CustomConverter<List<T>> and CustomConverter<List<T>> is not assignable from ListConverter<T> (which I checked with IsAssignableFrom() and IsSubclassOf() ).但是在我创建了一个通用类型CustomConverter<List<T>> ,我发现ListConverter<T>不是从CustomConverter<List<T>>派生的,并且CustomConverter<List<T>>不能从ListConverter<T> (我用IsAssignableFrom()IsSubclassOf()进行了检查。

I guess the reason is that generic type stands for more than one type before the generic parameters are assigned.我想原因是泛型类型在分配泛型参数之前代表不止一种类型。 This sounds weird but it is true.这听起来很奇怪,但确实如此。 The compiler doesn't know that the T in CustomConverter<List<T>> and ListConverter<T> stand for the same TYPE In fact, I can write it like CustomConverter<List<T>> and ListConverter<U> , and then you tell me the inheritance relationship between them.编译器不知道TCustomConverter<List<T>>ListConverter<T>站在同一类型其实,我能写出像CustomConverter<List<T>>ListConverter<U>然后你告诉我他们之间的继承关系。

And base type checking won't work here since ListConverter<T> and DictConverter<T,U> share the same root class.由于ListConverter<T>DictConverter<T,U>共享相同的根类,因此基本类型检查在这里ListConverter<T> This means if I look for ListConverter<T> , I'll get DictConverter<T,U> too with the base class checking method(hierarchy loop checking).这意味着如果我寻找ListConverter<T> ,我也会通过基类检查方法(层次循环检查)得到DictConverter<T,U> So I still have to make generic type, then check generic arguments and do type comparing.所以我仍然需要制作泛型类型,然后检查泛型参数并进行类型比较。

The point is that I need to look for the specific class whose generic parameters are used as the generic arguments in its parent class's generic parameter.关键是我需要查找其泛型参数用作其父类的泛型参数中的泛型参数的特定类。 Sort of twisted but now it is clear.有点扭曲,但现在很清楚。

Here is the final Convertion solution:这是最终的转换解决方案:

    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);
        }

I also checked GetGenericArguments().Length in case List<T> messes with Dictionary<TKey,TValue> .我还检查了GetGenericArguments().Length以防List<T>Dictionary<TKey,TValue>

Note: some custom extension methods are used.注意:使用了一些自定义扩展方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM