tca*_*vin 13 c# typeconverter visual-studio-2010 asp.net-4.0 asp.net-web-api
我想创建一个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);
}
}
Run Code Online (Sandbox Code Playgroud)
问题在于你不能在这一行中使用泛型,它是不允许的:
[TypeConverter(typeof(WrapperConverter<T>))]
public class Wrapper<T>
Run Code Online (Sandbox Code Playgroud)
我的下一个方法是尝试定义一个可以处理任何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);
}
Run Code Online (Sandbox Code Playgroud)
在ConvertFrom
我有最大的问题,因为我无法知道哪个Wrapper类将转换字符串转换为.
我已经创建了几个用于ASP.NET 4 Web API框架的自定义类型和TypeConverters,这也是我需要使用它的地方.
我想另一件事是在运行时所看到分配我的转换器通用版在这里,但框架的WebAPI不尊重它(意思是,该转换器从未创建).
最后一点,我使用的是.NET 4.0和VS 2010.
tca*_*vin 37
我通过创建一个单一的转换器来解决这个问题,该转换器可以处理从我的泛型类中衍生的所有类型.通过捕获构造函数中的信息解决了在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");
}
}
Run Code Online (Sandbox Code Playgroud)
我花了很长时间才发现.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);
}
}
Run Code Online (Sandbox Code Playgroud)
您只需要将 TypeDescriptionProviderAttribute 应用到目标类,如:
[TypeDescriptionProvider(typeof(FooTypeDescriptionProvider))]
public class Foo<T> { }
Run Code Online (Sandbox Code Playgroud)
进而
TypeDescriptor.GetConverter(typeof(Foo))
将按预期工作。
归档时间: |
|
查看次数: |
4752 次 |
最近记录: |