Generics 具有静态成员的F#泛型类型。这有可能吗?

Generics 具有静态成员的F#泛型类型。这有可能吗?,generics,f#,Generics,F#,我有以下情况: 一,。 有许多(20-40)结构非常相似的缓慢变化的数据类型 二,。 低级别的每个数据类型都由唯一的(对于类型)字符串标签和唯一的(对于类型)键(通常是字符串或长键)表示。密钥不会更改,但标签(平均)可能每年更新不到一次 三,。 我将每个这样的数据类型“升级”为F#DU,这样每个标签/键都有一个DU案例。这是必需的,因为一些高级代码需要进行模式匹配。因此,在一种罕见的情况下,当类型更新时,我希望在情况发生变化时出现编译错误。因此,对于每种类型,我生成/编写如下代码: type C

我有以下情况:

一,。 有许多(20-40)结构非常相似的缓慢变化的数据类型

二,。 低级别的每个数据类型都由唯一的(对于类型)字符串标签和唯一的(对于类型)键(通常是字符串或长键)表示。密钥不会更改,但标签(平均)可能每年更新不到一次

三,。 我将每个这样的数据类型“升级”为F#DU,这样每个标签/键都有一个DU案例。这是必需的,因为一些高级代码需要进行模式匹配。因此,在一种罕见的情况下,当类型更新时,我希望在情况发生变化时出现编译错误。因此,对于每种类型,我生成/编写如下代码:

type CollegeSize = 
    | VerySmall
    | Small
    | Medium
    | Large
    | VeryLarge
with
    static member all = 
        [|
            (CollegeSize.VerySmall, "Very small (less than 2,000 students)", 1L)
            (CollegeSize.Small, "Small (from 2,001 to 5,000 students)", 2L)
            (CollegeSize.Medium, "Medium (from 5,001 to 10,000 students)", 3L)
            (CollegeSize.Large, "Large (from 10,000 to 20,000 students)", 4L)
            (CollegeSize.VeryLarge, "Very large (over 20,000 students)", 5L)
        |]
四,。 所有这些类型都在两个地方使用:F#engine(它进行一些计算)和一个网站。F#引擎只适用于DU情况。不幸的是,现在的网站大多基于字符串。因此,web团队希望对几乎所有类型的操作使用基于字符串的方法,并且他们正在使用C#

五,。 因此,我创建了两个通用工厂:

type CaseFactory<'C, 'L, 'K when 'C : comparison and 'L : comparison and 'K : comparison> = 
    {
        caseValue : 'C
        label : 'L
        key : 'K
    }

// DU factory: 'C - case, 'L - label, 'K - key
type UnionFactory< 'C, 'L, 'K when 'C : comparison and 'L : comparison and 'K : comparison> (all : array< 'C * 'L * 'K> ) =
    let map = all |> Array.map (fun (c, l, _) -> (c, l)) |> Map.ofArray
    let mapRev = all |> Array.map (fun (c, l, _) -> (l, c)) |> Map.ofArray
    let mapVal = all |> Array.map (fun (c, _, k) -> (c, k)) |> Map.ofArray
    let mapValRev = all |> Array.map (fun (c, _, k) -> (k, c)) |> Map.ofArray

    let allListValue : System.Collections.Generic.List<CaseFactory< 'C, 'L, 'K>> = 
        let x = 
            all 
            |> List.ofArray
            |> List.sortBy (fun (_, s, _) -> s)
            |> List.map (fun (c, s, v) -> { caseValue = c; label = s; key = v } : CaseFactory< 'C, 'L, 'K>)
        new System.Collections.Generic.List<CaseFactory< 'C, 'L, 'K>> (x)

    //Use key, NOT label to create.
    [<CompiledName("FromKey")>]
    member this.fromKey (k : 'K) : 'C = mapValRev.Item (k)

    // For integer keys you can pass "1" instead of 1
    [<CompiledName("FromKeyString")>]
    member this.fromKeyString (s : string) : 'C = this.fromKey (convert s)

     //Use key, NOT label to create.
    [<CompiledName("TryFromKey")>]
    member this.tryFromKey (k : 'K) : 'C option = mapValRev.TryFind k

    [<CompiledName("TryFromKeyString")>]
    member this.tryFromKeyString (s : string) : 'C option = mapValRev.TryFind (convert s)

     //Use key, NOT label to create.
    [<CompiledName("TryFromKey")>]
    member this.tryFromKey (k : 'K option) : 'C option = 
        match k with 
        | Some x -> this.tryFromKey x
        | None -> None

    [<CompiledName("AllList")>]
    member this.allList : System.Collections.Generic.List< CaseFactory< 'C, 'L, 'K>> = allListValue

    [<CompiledName("FromLabel")>]
    member this.fromLabel (l : 'L) : 'C = mapRev.[l]

    [<CompiledName("TryFromLabel")>]
    member this.tryFromLabel (l : 'L) : 'C option = mapRev.TryFind l

    [<CompiledName("TryFromLabel")>]
    member this.tryFromLabel (l : 'L option) : 'C option = 
        match l with 
        | Some x -> this.tryFromLabel x
        | None -> None

    [<CompiledName("GetLabel")>]
    member this.getLabel (c : 'C) : 'L = map.[c]

    [<CompiledName("GetKey")>]
    member this.getKey (c : 'C) : 'K = mapVal.[c]
类型CaseFactory=
{
案例价值:'C
标签:L
键:K
}
//DU工厂:C-外壳,L-标签,K-键
当“C:比较”和“L:比较”以及“K:比较”时,键入UnionFactory<'C',L',K>(全部:数组<'C*'L*'K>)=
让map=all |>Array.map(fun(c,l,|)->(c,l))|>map.of数组
让mapRev=all |>Array.map(fun(c,l,|)->(l,c))|>map.of数组
设mapVal=all |>Array.map(fun(c,|,k)->(c,k))|>map.of数组
让mapValRev=all |>Array.map(fun(c,|,k)->(k,c))|>map.of数组
let allListValue:System.Collections.Generic.List)
新System.Collections.Generic.List>=allListValue
[]
成员this.fromLabel(l:'l):'C=mapRev.[l]
[]
成员this.tryFromLabel(l:'l):'C option=mapRev.TryFind l
[]
成员this.tryFromLabel(l:'l选项):'C选项=
匹配
|一些x->this.tryFromLabel x
|无->无
[]
成员this.getLabel(c:'c):'L=map。[c]
[]
成员this.getKey(c:'c):'K=mapVal。[c]
六,。 在这一点上,如果我为每种类型创建一个带有单例的通用工厂,那么一切都像时钟一样工作,如:

type CollegeSizeFactory private () =
    inherit UnionFactory<CollegeSize, string, int64> (CollegeSize.all)
    static let instance = CollegeSizeFactory ()
type CollegeSizeFactory private()=
继承UnionFactory(CollegeSize.all)
静态let实例=CollegeSizeFactory()
七,。 …除了web团队不希望每次调用泛型工厂的方法时都使用实例之外。所以,我最后写了:

type CollegeSizeFactory private () =
    inherit UnionFactory<CollegeSize, string, int64> (CollegeSize.all)
    static let instance = CollegeSizeFactory ()
    static member Instance = instance

    static member FromLabel s = CollegeSizeFactory.Instance.fromLabel s
    static member FromKey k = CollegeSizeFactory.Instance.fromKey k
    static member FromKeyString s = CollegeSizeFactory.Instance.fromKeyString s
type CollegeSizeFactory private()=
继承UnionFactory(CollegeSize.all)
静态let实例=CollegeSizeFactory()
静态成员实例=实例
静态成员FromLabel s=CollegeSizeFactory.Instance.FromLabel s
静态成员FromKey=CollegeSizeFactory.Instance.FromKey
静态成员FromKeyString s=CollegeSizeFactory.Instance.FromKeyString s
问题是,如果明天他们需要更多的快捷方式(比如标签中的静态成员),那么所有通用工厂的实现都必须手动更新

理想情况下,我想要一个单行程序,这样对于我需要的每个工厂,我都可以从泛型类型继承,比如:

type CollegeSizeFactory private () =
    inherit UnionFactory<CollegeSize, string, int64> (CollegeSize.all)
type CollegeSizeFactory private()=
继承UnionFactory(CollegeSize.all)
然后自动获取可能需要的所有内容,包括所有静态成员。我想知道这是否可能,如果可能,那么具体是怎样的


非常感谢。

我建议您放弃单例的想法,改用实例成员,完全避免这个问题。一开始单身是个坏主意

一种方法是使用一个带有工厂的模块,可能是懒散地进行评估(尽管我认为在您的场景中这不是一个问题,创建工厂并不昂贵)。然后您可以直接使用该模块,或者通过要创建的类型上的静态成员重新公开该模块,例如

type CollegeSizeFactory () =
    inherit UnionFactory<CollegeSize, string, int64> (CollegeSize.all)

module Factories = 
    let collegeSize = lazy CollegeSizeFactory()

type CollegeSize with
    static member Factory = Factories.collegeSize.Value

CollegeSize.Factory.tryFromKey 1
type CollegeSizeFactory()=
继承UnionFactory(CollegeSize.all)
模块工厂=
let collegeSize=懒惰的CollegeSizeFactory()
类型学院化
静态成员工厂=Factories.collegeSize.Value
CollegeSize.Factory.tryFromKey 1
您的问题的设计空间相当大,毫无疑问,这不是找到的最佳解决方案,但我觉得这是一个很好的第一步,可以通过简单的重构实现


但老实说,您可能可以直接对
所有成员进行编码,而不是预先计算这些查找。它们可能很小,以至于性能差异不足以维持这种更复杂的设置。

问题太长太复杂了。试着用一个更简单、更小的例子来说明你需要什么和你拥有什么。此外,代码格式设置已全部关闭。此外,“ааааааааааааааааа。试着说“像发条一样”或“像个符咒”。另外,试着看看。