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。
我想要的是通过反射获取所有类,然后获取从传入的泛型类型继承的特定类。
e.g。
(1)
List<int>
- &gt;(2)获取通用类型定义 ==&gt;
List<T>
- &gt;(3)制作通用 ==&gt;
BaseGenericType<List<T>>
- &gt;(4)查找子类 ==&gt;
SubGenericType<T>
(5)制作通用 ==&gt;
SubGenericType<int>
在步骤(4)中,我找不到任何内容,尽管我确实拥有SubGenericType<T>
。那是为什么?
答案 0 :(得分:3)
一旦我编写了这个方法来检查泛型类型继承:
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
接口而不使用泛型参数。有些你只是不关心泛型类型,只想访问不依赖于泛型类型的成员。有时您只想检查是否其中之一。 和您可以使用类型差异。
答案 1 :(得分:1)
最后我明白了。 这是非常好的解决方案。为了详细解释,我必须介绍一些非抽象的编码:
这是一个价值转换器。我的目的很简单,就是让用户添加自己的值转换器。在转换步骤中,我将首先检查内置类型的转换器(如IConvertible
),如果找不到,我将在当前正在执行的程序集中搜索继承特定{{1}的所有自定义转换器类我提供的课程。并且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
值转换为的类型。
e.g。
string
这很容易处理,因为转换目标类型不是通用的。我需要做的就是获得实现public class Int32Converter:CustomConverter<int>
{
}
的所有类型,并使用给定的ICustomConverter
从CustomConverter<T>
创建一个通用类型,从而int
。然后我为那些派生自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>>
(我使用ListConverter<T>
和IsAssignableFrom()
核对)。
我想原因是泛型类型在分配泛型参数之前代表多种类型。
这听起来很奇怪,但这是真的。 编译器不知道IsSubclassOf()
和T
中的CustomConverter<List<T>>
代表相同的TYPE
实际上我可以像ListConverter<T>
和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>
混淆。
注意:使用了一些自定义扩展方法。