通常将通用TypeConverter应用于现有泛型类型

时间:2014-11-02 00:55:59

标签: .net generics reflection f#

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

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

我希望将此转换器应用于现有的通用类型,例如Option&lt;&quot; t&gt;。此外,我希望通常这样做,以便Option会自动使用AlgebraicConverter&gt;对于它的转换器。

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

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

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

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

然而,由于两个原因,这是不能令人满意的 -

1)我无法事先知道用户可能需要的不同类型实例,以及

2)尝试将此转换器应用于每个可能的实例化都是不切实际的。

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

C#&#39; rs,请随时回答这个问题;只有这个问题中使用的示例类型才特定于F#。

2 个答案:

答案 0 :(得分:4)

不幸的是,这是不可能的。问题必须包括:

  1. 您希望在运行时向任何类型无论添加额外属性 通用定义是option< >。但是,你只能 甚至将额外属性添加到通用option< > 本身, 使用typedefof<int option>代替typeof<int option>。但是这个 保留特定的typeof<int option>typeof<float option>等。 稍后,当组件模型有一个要转换的实例时,它会查找 TypeConverterAttribute仅限于实例的特定类型,而不是任何通用类型 输入它可能与。

  2. 相关联
  3. 即使存在解决第1部分的方法, 您仍然需要决定添加到该类型的特定AlgebraicConverter 描述符系统。您无法添加通用AlgebraicConverter< >。然而, 这更像是一个设计问题,可以轻松解决。

  4. 变通方法

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

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

    另一方面,如果要坚持AlgebraicConverter<'T>,则必须为每个特定目标类型添加新实例。

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

答案 1 :(得分:0)

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

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

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