【问题标题】:Generic type inheritance泛型类型继承
【发布时间】:2015-09-15 09:27:11
【问题描述】:
public class BaseGenericType<T>
{
}

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

我上面有两种泛型类型,一种从另一种继承,但仍然是泛型的。 我想不通的奇怪事情是typeof(SubGenericType&lt;&gt;).IsSubclassOf(typeof(BaseGenericType&lt;&gt;)) 返回 false。而typeof(SubGenericType&lt;&gt;).IsSubclassOf(typeof(BaseGenericType&lt;List&lt;&gt;&gt;)) 仍然返回 false。我试过GetGenericTypeDefinition()MakeGenericType()GetGenericArguments() 来检查继承,还是不行。但typeof(SubGenericType&lt;int&gt;).IsSubclassOf(typeof(BaseGenericType&lt;List&lt;int&gt;&gt;)) 返回真。

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

例如

(1)List&lt;int&gt; -->

(2)获取泛型类型定义==> List&lt;T&gt; -->

(3)使通用==> BaseGenericType&lt;List&lt;T&gt;&gt; -->

(4)查找子类==> SubGenericType&lt;T&gt;

(5)通用==> SubGenericType&lt;int&gt;

在步骤 (4) 中,虽然我实际上有 SubGenericType&lt;T&gt;,但我什么也没找到。这是为什么呢?

【问题讨论】:

    标签: c# generics inheritance reflection


    【解决方案1】:

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

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

    这返回真:

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

    虽然它不检查接口。

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

    【讨论】:

    • 谢谢你!我已经使用一个简单的解决方案解决了这个问题。我稍后会发布它。正如您提到的interface,我确实有一个接口约束,但是使 SubClassFinding 步骤变得复杂的是泛型参数本身就是泛型类型,或者更糟糕的是:递归。我会试试你的解决方案,它看起来很整洁。再次感谢。
    • IsSubclassOfOpenGeneric(typeof(BaseGenericType&lt;&gt;), typeof(SubGenericType&lt;&gt;)) 它确实有效!我猜我应该使用type.BaseType 循环作为根类型(Object 除外)。 :D
    • 当两个参数是同一个泛型类时,此代码错误地返回 true。我添加了这一行“if (generic == toCheck) return false;”作为方法 IsSubclassOfOpenGeneric 的第一行,当方法的两个参数相同时,使该方法返回 false。代码经过测试。它使行为与 .NET Framework 方法 IsSubclassOf 一致。此代码返回 false: var result = typeof(GenericBaseClass).IsSubclassOf(typeof(GenericBaseClass); 版主拒绝了我的编辑,因此如果您要在生产中使用此代码,请添加此更改。跨度>
    【解决方案2】:

    最后,我想通了。 这就是解决方案。为了详细解释,我不得不介绍一些非抽象编码:

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

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

        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&lt;T&gt; 创建一个泛型类型,因此CustomConverter&lt;int&gt;。然后我过滤那些派生自CustomConverter&lt;int&gt;的类,在这里我找到了Int32Converter

    后来我遇到了这种情况:

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

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

    我使用相同的过程来处理它们。但是在我做了一个泛型CustomConverter&lt;List&lt;T&gt;&gt;之后,我发现ListConverter&lt;T&gt;不是派生自CustomConverter&lt;List&lt;T&gt;&gt;CustomConverter&lt;List&lt;T&gt;&gt;是不能赋值的 ListConverter&lt;T&gt;(我与IsAssignableFrom()IsSubclassOf() 核对过)。

    我猜原因是泛型类型在分配泛型参数之前代表不止一种类型。 这听起来很奇怪,但这是真的。 编译器不知道CustomConverter&lt;List&lt;T&gt;&gt;ListConverter&lt;T&gt; 中的T 代表相同的TYPE 其实我可以写成CustomConverter&lt;List&lt;T&gt;&gt;ListConverter&lt;U&gt;,然后你告诉我它们之间的继承关系。

    因为ListConverter&lt;T&gt;DictConverter&lt;T,U&gt; 共享同一个根类,所以基类型检查在这里不起作用。这意味着如果我寻找ListConverter&lt;T&gt;,我也会通过基类检查方法(层次循环检查)得到DictConverter&lt;T,U&gt;。所以我还是要做泛型类型,然后检查泛型参数并进行类型比较。

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

    这是最终的转化解决方案:

        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&lt;T&gt;Dictionary&lt;TKey,TValue&gt; 混淆。

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

    【讨论】:

      猜你喜欢
      • 2018-09-27
      • 2021-10-11
      • 2018-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-11
      • 1970-01-01
      相关资源
      最近更新 更多