无法为泛型类型创建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>实例的非通用转换器。反射和泛型的混合让我纠结于如何实现ConvertToConvertFrom方法。

例如,我的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。

无法为泛型类型创建TypeConverter

我通过创建一个转换器来解决这个问题,该转换器可以继承从我的泛型类派生的所有类型。了解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))将按预期工作。