【问题标题】:Cannot create a TypeConverter for a generic type无法为泛型类型创建 TypeConverter
【发布时间】:2013-01-27 05:38: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&lt;T&gt; 实例的单个非泛型转换器。反射和泛型的混合让我难以理解如何实现两种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 类。

我创建了几个自定义类型和 TypeConverters 用于 ASP.NET 4 Web API 框架,这也是我需要使用它的地方。

我尝试的另一件事是在运行时分配通用版本的转换器,如 here 所示,但 WebAPI 框架不尊重它(意味着从未创建转换器)。

最后一点,我使用的是 .NET 4.0 和 VS 2010。

【问题讨论】:

  • 我之前已经解决了这个问题,我相信我使用 dynamic 来转换 T 并使用 typeof 。我明天应该可以发布我的解决方案,因为我目前无法访问代码。
  • @awright18 谢谢,但我没有我需要的东西。我的问题主要是如何为泛型类型创建和关联 TypeConverter。

标签: c# visual-studio-2010 asp.net-web-api asp.net-4.0 typeconverter


【解决方案1】:

我通过创建一个可以处理从我的泛型类派生的所有类型的单个转换器解决了这个问题。了解 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 类的一部分。

希望这一切对下一个人有所帮助。

【讨论】:

  • 不错!谢谢你的提示。也解决了我认为我无法最终知道目标类型的问题。虽然如果没有记录在案,但可能会受到未来的破坏。
  • 嗯,我去看看。该项目仍在 4.0 中,因此我无法确认它是否仅适用于该版本。
  • 我想给定的答案对你有用,因为 ASP.NET 加载 TypeConverter 的方式可能与我正在尝试的 WPF 不同。 WPF 似乎正在寻找一个无参数的构造函数。
  • 你能发布一个完整的课程吗?
【解决方案2】:

虽然@tcarvin 的回答非常有趣——它适用于我在 .NET Framework 4.6.1 中,而且从我看到的in the code 它也应该适用于 .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)) 将按预期工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多