无法为泛型类型创建TypeConverter
本文关键字:创建 TypeConverter 泛型类型 | 更新日期: 2023-09-27 17:58:40
我想为泛型类创建一个TypeConverter
,如下所示:
[TypeConverter(typeof(WrapperConverter<T>))]
public class Wrapper<T>
{
public T Value
{
// get & set
}
// other methods
}
public class WrapperConverter<T> : TypeConverter<T>
{
// only support To and From strings
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
T inner = converter.ConvertTo(value, destinationType);
return new Wrapper<T>(inner);
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(System.String))
{
Wrapper<T> wrapper = value as Wrapper<T>();
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
return converter.ConvertTo(wrapper.Value, destinationType);
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
问题来了,你不能在这行中有一个泛型,它是不允许的:
[TypeConverter(typeof(WrapperConverter<T>))]
public class Wrapper<T>
我的下一个方法是尝试定义一个可以处理任何Wrapper<T>
实例的非通用转换器。反射和泛型的混合让我纠结于如何实现ConvertTo
和ConvertFrom
方法。
例如,我的ConvertTo看起来是这样的:
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(System.String)
&& value.GetType().IsGenericType)
{
// 1. How do I enforce that value is a Wrapper<T> instance?
Type innerType = value.GetType().GetGenericArguments()[0];
TypeConverter converter = TypeDescriptor.GetConverter(innerType);
// 2. How do I get to the T Value property? Introduce an interface that Wrapper<T> implements maybe?
object innerValue = ???
return converter.ConvertTo(innerValue, destinationType);
}
return base.ConvertTo(context, culture, value, destinationType);
}
在ConvertFrom
中,我遇到了最大的问题,因为我无法知道将插入字符串转换为哪个Wrapper类。
我已经创建了几个用于ASP的自定义类型和TypeConverter。NET 4 Web API框架,这也是我需要使用它的地方。
我尝试的另一件事是在运行时分配转换器的通用版本,如图所示,但WebAPI框架不尊重它(这意味着转换器从未创建)。
最后一个音符,我正在使用。NET 4.0和VS 2010。
我通过创建一个转换器来解决这个问题,该转换器可以继承从我的泛型类派生的所有类型。了解ConvertFrom中的泛型arg T的大问题通过捕获构造函数中的信息来解决,如下所示。
public MyGenericConverter(Type type)
{
if (type.IsGenericType
&& type.GetGenericTypeDefinition() == typeof(MyGenericClass<>)
&& type.GetGenericArguments().Length == 1)
{
_genericInstanceType = type;
_innerType = type.GetGenericArguments()[0];
_innerTypeConverter = TypeDescriptor.GetConverter(_innerType);
}
else
{
throw new ArgumentException("Incompatible type", "type");
}
}
我花了很长时间才发现。NET基础结构反射式调用此构造函数重载(如果已定义)。它不是文档化的TypeConverter类的一部分。
希望这一切能帮助下一个人。
尽管@tcarvin的答案非常有趣,但它在中对我有效。NET Framework 4.6.1,从我在代码中看到的情况来看,它也应该可以工作。NET Core,有一种使用TypeDescriptionProviderAttribute
的替代解决方案,它不依赖于他描述的实现细节(接受Type
类型参数的构造函数)。
拥有:
public class FooTypeConverter<T> : TypeConverter { ... }
public class FooTypeDescriptor : CustomTypeDescriptor
{
private Type objectType;
public FooTypeDescriptor(Type objectType)
{
this.objectType = objectType;
}
public override TypeConverter GetConverter()
{
var genericArg = objectType.GenericTypeArguments[0];
var converterType = typeof(FooTypeConverter<>).MakeGenericType(genericArg);
return (TypeConverter)Activator.CreateInstance(converterType);
}
}
public class FooTypeDescriptionProvider : TypeDescriptionProvider
{
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return new FooTypeDescriptor(objectType);
}
}
您只需要将TypeDescriptionProviderAttribute应用于目标类,如:
[TypeDescriptionProvider(typeof(FooTypeDescriptionProvider))]
public class Foo<T> { }
然后
TypeDescriptor.GetConverter(typeof(Foo))
将按预期工作。