直接在 F# 中匹配类型(不是对象,而是实际的 System.Type)

mam*_*mcx 5 f# types pattern-matching

我知道如何在对象的类型上进行匹配,但是如何直接在类型对象上进行匹配?

这不起作用:

    let toType = p.PropertyType 

    match toType with
    | System.Enum -> 
    | System.Int32 -> 
Run Code Online (Sandbox Code Playgroud)

PD:是的,我需要匹配类型。我没有物体,因为我正在反思

Fyo*_*kin 6

您无法对其System.Type自身进行匹配,因为它不是 F# 可解构类型。同样的方式你也无法匹配,例如 onStreamReader或 onStringBuilder等。

但你可以很好地比较类型,例如:

if t = typeof<Enum> then ...
elif t = typeof<Int32> then ...
else ...
Run Code Online (Sandbox Code Playgroud)

但是,请记住,这只会给您带来严格的平等。它不会给你子类型。例如,typeof<DayOfWeek> <> typeof<Enum>
为了检查子类型,请使用以下Type.IsAssignableFrom方法

if typeof<Enum>.IsAssignableFrom t then ...
elif typeof<Int32>.IsAssignableFrom t then ...
else ...
Run Code Online (Sandbox Code Playgroud)

(请注意,对于Int32简单的比较就足够了,因为它Int32是密封类型,所以它不能有子类型;但IsAssignableFrom为了保持一致性,我仍然保留在那里)


如果你真的想使用match语法,你总是可以让自己成为一个活动模式

不幸的是,您不能在模式中使用尖括号(无论出于何种原因),所以这match x with IsType typeof<Enum>是不可能的。但是您可以在模式中使用引号,并且引号中可以包含尖括号,因此您可以这样做match x with IsType <@ typeof<Enum> @>。不幸的是,这意味着活动模式将相当复杂并且性能不那么好:

let (|IsType|_|) (a: FSharp.Quotations.Expr<System.Type>) (t: System.Type) : unit option = 
    match a with
    | FSharp.Quotations.Patterns.Call (None, m, []) when m.Name = "TypeOf" -> 
        let testAgainst = m.GetGenericArguments().[0]
        if testAgainst.IsAssignableFrom t
            then Some()
            else None
    | _ -> 
        None

match t with
| IsType <@ typeof<Enum> @> -> "enum"
| IsType <@ typeof<Int32> @> -> "int"
| _ -> "don't know"
Run Code Online (Sandbox Code Playgroud)

这是相当重要的,所以我不推荐它。只是作为一种心理锻炼:-)