最后,我想通了。
这就是解决方案。为了详细解释,我不得不介绍一些非抽象编码:
这是关于一个价值转换器。我的目的很简单,让用户添加自己的价值转换器。在转换步骤中,我将首先检查内置类型的转换器(如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 的类型,并使用给定的int 从CustomConverter<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>>是不能赋值的
ListConverter<T>(我与IsAssignableFrom() 和IsSubclassOf() 核对过)。
我猜原因是泛型类型在分配泛型参数之前代表不止一种类型。
这听起来很奇怪,但这是真的。 编译器不知道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> 混淆。
注意:使用了一些自定义扩展方法。