代码之家  ›  专栏  ›  技术社区  ›  Daniel

使用“flexible”类型参数对泛型类型进行模式匹配

  •  6
  • Daniel  · 技术社区  · 15 年前
    match value with
    | :? list<#SomeType> as l -> l //Is it possible to match any list of a type derived from SomeType?
    | _ -> failwith "doesn't match"
    
    5 回复  |  直到 15 年前
        2
  •  9
  •   Tomas Petricek    15 年前

    如前所述,无法直接执行此操作(模式匹配只能绑定值,但不能绑定新的类型变量)。除了 IEnumerable

    match box value with 
    | :? System.Collections.IEnumerable as l when 
         // assumes that the actual type of 'l' is 'List<T>' or some other type
         // with single generic type parameter (this is not fully correct, because
         // it could be other type too, but we can ignore this for now)
         typedefof<SomeType>.IsAssignableFrom
           (value.GetType().GetGenericArguments().[0]) -> 
       l |> Seq.cast<SomeType>
    | _ -> failwith "doesn't match"
    

    代码测试值是否为非泛型 I可数 SomeType . 在这种情况下,我们得到了一个派生类型的列表,所以我们可以将它转换为 值(这与处理派生类型的值列表略有不同,但对于实际目的来说应该无关紧要)。

        3
  •  2
  •   Daniel    15 年前

    后来我需要类似的东西来匹配懒惰的实例。这是我的解决方案,以防有人觉得有用。

    let (|Lazy|_|) (value : obj) =
        if box value <> null then
            let typ = value.GetType()
            if typ.IsGenericType && typ.GetGenericTypeDefinition() = typedefof<Lazy<_>> then
                Some(typ.GetGenericArguments().[0])
            else None
        else None
    

    match value with
    | Lazy typ when typeof<SomeType>.IsAssignableFrom(typ) -> (value :?> Lazy<_>).Value
    | _ -> failwith "not an instance of Lazy<#SomeType>"
    
        4
  •  1
  •   Remko    12 年前

    不是最干净,但很有效:

    let matchType<'T> () =
        try
            let o = Activator.CreateInstance<'T> ()
            match box o with
            | :? Type1 -> printfn "Type1"
            | :? Type2 -> printfn "Type2"
            | _ -> failwith "unknown type"
        with
        | ex -> failwith "%s" (ex.ToString())
    
        5
  •  0
  •   Marc Sigrist    15 年前

    F# 2.0 specification ,第。14.5.2(解决子类型约束),它将不起作用,因为:“F#泛型类型不支持协方差或逆变。”