泛型继承
Generic type inheritance
public class BaseGenericType<T>
{
}
public class SubGenericType<T>: BaseGenericType<List<T>>
{
}
我上面有两个泛型,一个继承自另一个,但仍然是泛型。
我想不通的奇怪事情是 typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<>))
returns 是假的。而且 typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<List<>>))
仍然 returns 错误。我已经尝试 GetGenericTypeDefinition()
和 MakeGenericType()
以及 GetGenericArguments()
来检查继承,但仍然无法正常工作。但是 typeof(SubGenericType<int>).IsSubclassOf(typeof(BaseGenericType<List<int>>))
returns 是真的。
我想要的是通过反射获取所有 classes 然后获取特定的 class 继承自传入的通用类型。
例如
(1)List<int>
-->
(2)get generic type definition ==> List<T>
-->
(3)make generic ==> BaseGenericType<List<T>>
-->
(4)find subclass ==> SubGenericType<T>
(5)make generic ==> 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;
}
这 returns 正确:
IsSubclassOfOpenGeneric(typeof(BaseGenericType<>), typeof(SubGenericType<int>))
虽然它不检查接口。
顺便说一句,通常如果你有这样的关系,并且你自己写了所有类,考虑使用接口。它更容易处理。例如,您可以有一个 IGenericType
接口 而没有 通用参数。有时您只是不关心泛型类型,只想访问不依赖于泛型类型的成员。有时您只想检查它是否 是 其中之一。 并且你可以使用类型差异。
我终于明白了。
这就是解决方案。为了详细解释,我不得不介绍一些非抽象的编码:
这是关于一个值转换器。我的目的很简单,让用户添加自己的价值转换器。在转换步骤中,我将首先检查内置类型的转换器(如IConvertible
),如果没有找到,我将首先在当前执行的程序集中搜索所有继承一个自定义转换器classes具体的 abstract
class 由我提供。 interface
由 abstract
class 实现,为以后的反射做约束。然后我过滤那些反射的 classes 以找到匹配的。
这是基础 class 和接口(全部嵌套):
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);
}
}
我已将接口在父级 class 中设为私有并显式实现。这样方法CallConvert()
就不会被外部调用了。
通用参数 T
是要将 string
值转换为的类型。
例如
public class Int32Converter:CustomConverter<int>
{
}
这很容易处理,因为转换目标类型不是通用的。我需要做的就是获取所有实现 ICustomConverter
的类型,并使用给定的 int
从 CustomConverter<T>
创建一个通用类型,因此 CustomConverter<int>
。然后我过滤那些 classes 为派生自 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()
检查过)。
我猜是因为在泛型参数赋值之前,泛型代表了不止一种类型。
这听起来很奇怪,但却是事实。 编译器不知道CustomConverter<List<T>>
和ListConverter<T>
中的T
代表同一个TYPE
其实我可以写成CustomConverter<List<T>>
和ListConverter<U>
,然后你告诉我它们之间的继承关系
并且基类型检查在这里不起作用,因为 ListConverter<T>
和 DictConverter<T,U>
共享同一个根 class。这意味着如果我查找 ListConverter<T>
,我也会使用基本 class 检查方法(层次结构循环检查)得到 DictConverter<T,U>
。所以我仍然必须制作泛型类型,然后检查泛型参数并进行类型比较。
关键是我需要寻找特定的 class,其泛型参数用作其父 class 的泛型参数中的泛型参数。有点扭曲,但现在很清楚了。
这是最终的转换解决方案:
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>
混淆。
注意:使用了部分自定义扩展方法
public class BaseGenericType<T>
{
}
public class SubGenericType<T>: BaseGenericType<List<T>>
{
}
我上面有两个泛型,一个继承自另一个,但仍然是泛型。
我想不通的奇怪事情是 typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<>))
returns 是假的。而且 typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<List<>>))
仍然 returns 错误。我已经尝试 GetGenericTypeDefinition()
和 MakeGenericType()
以及 GetGenericArguments()
来检查继承,但仍然无法正常工作。但是 typeof(SubGenericType<int>).IsSubclassOf(typeof(BaseGenericType<List<int>>))
returns 是真的。
我想要的是通过反射获取所有 classes 然后获取特定的 class 继承自传入的通用类型。
例如
(1)
List<int>
-->(2)get generic type definition ==>
List<T>
-->(3)make generic ==>
BaseGenericType<List<T>>
-->(4)find subclass ==>
SubGenericType<T>
(5)make generic ==>
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;
}
这 returns 正确:
IsSubclassOfOpenGeneric(typeof(BaseGenericType<>), typeof(SubGenericType<int>))
虽然它不检查接口。
顺便说一句,通常如果你有这样的关系,并且你自己写了所有类,考虑使用接口。它更容易处理。例如,您可以有一个 IGenericType
接口 而没有 通用参数。有时您只是不关心泛型类型,只想访问不依赖于泛型类型的成员。有时您只想检查它是否 是 其中之一。 并且你可以使用类型差异。
我终于明白了。 这就是解决方案。为了详细解释,我不得不介绍一些非抽象的编码:
这是关于一个值转换器。我的目的很简单,让用户添加自己的价值转换器。在转换步骤中,我将首先检查内置类型的转换器(如IConvertible
),如果没有找到,我将首先在当前执行的程序集中搜索所有继承一个自定义转换器classes具体的 abstract
class 由我提供。 interface
由 abstract
class 实现,为以后的反射做约束。然后我过滤那些反射的 classes 以找到匹配的。
这是基础 class 和接口(全部嵌套):
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);
}
}
我已将接口在父级 class 中设为私有并显式实现。这样方法CallConvert()
就不会被外部调用了。
通用参数 T
是要将 string
值转换为的类型。
例如
public class Int32Converter:CustomConverter<int>
{
}
这很容易处理,因为转换目标类型不是通用的。我需要做的就是获取所有实现 ICustomConverter
的类型,并使用给定的 int
从 CustomConverter<T>
创建一个通用类型,因此 CustomConverter<int>
。然后我过滤那些 classes 为派生自 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()
检查过)。
我猜是因为在泛型参数赋值之前,泛型代表了不止一种类型。
这听起来很奇怪,但却是事实。 编译器不知道CustomConverter<List<T>>
和ListConverter<T>
中的T
代表同一个TYPE
其实我可以写成CustomConverter<List<T>>
和ListConverter<U>
,然后你告诉我它们之间的继承关系
并且基类型检查在这里不起作用,因为 ListConverter<T>
和 DictConverter<T,U>
共享同一个根 class。这意味着如果我查找 ListConverter<T>
,我也会使用基本 class 检查方法(层次结构循环检查)得到 DictConverter<T,U>
。所以我仍然必须制作泛型类型,然后检查泛型参数并进行类型比较。
关键是我需要寻找特定的 class,其泛型参数用作其父 class 的泛型参数中的泛型参数。有点扭曲,但现在很清楚了。
这是最终的转换解决方案:
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>
混淆。
注意:使用了部分自定义扩展方法