【问题标题】:Generically apply a generic TypeConverter to an existing generic type将泛型 TypeConverter 泛型应用于现有泛型类型
【发布时间】:2014-11-02 00:55:58
【问题描述】:

我编写了一个具有以下类型签名的泛型类型转换器 -

type AlgebraicConverter<'t> () =
    inherit TypeConverter ()
    ...

我希望将此转换器应用于现有的泛型类型,例如 Option。另外,我希望一般这样做,以便 Option 将自动使用 AlgebraicConverter> 作为其转换器。

因为我无法控制现有类型的定义,所以我无法通过以下声明以通常的方式指定自定义类型转换器 -

type [<TypeConverter (typeof<AlgebraicConverter<Option<'t>>>)>] Option<'t> = ...

到目前为止,我只能通过使用 TypeDescriptor.AddAttributes 方法将我的通用转换器应用于现有类型的特定类型实例化 -

TypeDescriptor.AddAttributes (typeof<Option<int>>, TypeConverterAttribute typeof<AlgebraicConverter<Option<int>>>) 

但是,这并不令人满意,原因有两个 -

1) 我无法提前知道我的用户可能需要哪些不同类型的实例化,并且

2) 无论如何,尝试将此转换器应用于所有可能的实例化是不切实际的。

我可以采用什么技术泛型将我的泛型类型转换器应用于现有的泛型类型?希望有一种令人满意的优雅方法来实现这一目标。

C#'rs,也请随意回答这个问题;只有此问题中使用的示例类型特定于 F#。

【问题讨论】:

    标签: .net generics reflection f#


    【解决方案1】:

    很遗憾,这是不可能的。问题有几个部分:

    1. 您想在运行时为任何类型 whatsoever 添加一个额外的属性 通用定义是option&lt; &gt;。但是,您只能 甚至将额外属性添加到通用option&lt; &gt;本身, 使用typedefof&lt;int option&gt; 而不是typeof&lt;int option&gt;。但是这个 保持特定的typeof&lt;int option&gt;typeof&lt;float option&gt; 等保持不变。 稍后,当组件模型有要转换的实例时,它会查找 TypeConverterAttribute 仅适用于实例的特定类型,而不适用于任何泛型 可能与之关联的类型。

    2. 即使存在解决第 1 部分的方法, 您仍然必须决定要添加到类型中的特定 AlgebraicConverter 描述符系统。您不能添加通用 AlgebraicConverter&lt; &gt;。然而, 这更像是一个设计问题,很容易解决。

    解决方法

    如果您坚持只使用 one 转换器,则必须使转换器非泛型并将其映射到 Object 类型。但是,该转换器随后将替换任何先前定义的转换器。在内部,转换器按目标子类型分支 (如果您喜欢这种设计,然后仍然可以委托给其他转换器)。

    type GlobalConverter() =
        inherit TypeConverter()
        // etc.
    
    TypeDescriptor.AddAttributes(
        typeof<obj>, 
        TypeConverterAttribute typeof<GlobalConverter>)
    

    另一方面,如果您想坚持使用AlgebraicConverter&lt;'T&gt;,则必须为每个特定目标类型添加一个新实例。

    let addAlgebraicConverter<'T> = 
        TypeDescriptor.AddAttributes(
            typeof<'T>,
            TypeConverterAttribute typeof<AlgebraicConverter<'T>>) 
        |> ignore
    
    addAlgebraicConverter<int>
    addAlgebraicConverter<int option>
    addAlgebraicConverter<decimal>
    addAlgebraicConverter<decimal option>
    

    【讨论】:

    • 没有适合您处方的解决方法(仅使用通用转换器的一个实例),但我已使用其他解决方法编辑了答案。
    • 似乎我需要以某种方式使我的转换器成为非通用的。也许我应该尝试朝那个方向前进?
    • 所以我试图朝那个方向前进,但这使得 AlgebraicConverter 没有足够的类型信息来实现 ConvertFrom 等,EG - 它不知道它实际上应该转换为的类型...
    • 所以我继续并完全停止使用 ConvertFrom 功能,使上述问题变得毫无意义。然而,我不得不手动规避我的 PropertyGrid 对它的使用,但使用了相当丑陋的 hack。旅程还在继续……
    • 我的状态是这样的——现在我已经通过删除它的类型参数来概括 AlgebraicConverter,我可以通过赋予它们属性来让它在我自己的类型上工作。但是,即使进行了泛化并将 TypeDescriptor.AddAttributes 与 typedefof 一起使用,我仍然无法促使 TypeDescriptor.GetConverter 返回现有类型的 AlgebraicConverter。同样不幸的是,我无法将 AlgebraicConverter 分配给所有类型,因为我必须在 ConvertFrom 中进行修改以使其与 PropertyGrid 配合得很好。我似乎陷入了僵局,虽然我想已经取得了一些进展。
    【解决方案2】:

    尝试使用Option类的静态构造函数:

    static Option()
    {
        TypeDescriptor.AddAttributes (typeof<Option<T>>, TypeConverterAttribute typeof<AlgebraicConverter<Option<T>>>) 
    }
    

    当我遇到同样的问题时,这对我有用

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-14
      • 1970-01-01
      • 1970-01-01
      • 2013-01-27
      • 2016-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多