当值为“无”时动态确定选项的类型

时间:2014-02-18 13:29:51

标签: f# optional

动态获取Option类型存在一些困难。假设我有一个功能:

let printType x =
   if (box x) = null then printfn "the type is 'null'"
   else printfn "the type is %A" (x.GetType())

我们在这里有输出:

printType 3          // the type is System.Int32
printType (Some(3))  // the type is Microsoft.FSharp.Core.FSharpOption`1[System.Int32]
printType None       // the type is null
printType null       // the type is null

获取表达式的类型时,如何区分None和null?

3 个答案:

答案 0 :(得分:7)

在运行时,选项None值表示为null,因此您无法确定其运行时类型。但是,您可以编写一个通用函数来打印选项的静态类型:

let printType (x:'T option) =
  printfn "Static type is: %s" (typeof<'T>.Name)

根据您的需要,这可能会或可能不会满足您的需求。

printType (None : int option)     // Int32
printType (None : string option)  // String 
printType None                    // Object (the default used by the inference)

编辑如果您希望能够在任何参数上调用该函数,您可以像我的示例中一样使用typeof<'T>以及Matthew解决方案中的其余逻辑。以下内容与Matthew的代码片段完全相同(但没有充分理由不引用引号):

let printType (x:'T) =
  let typeOfX = typeof<'T>
  if not <| FSharpType.IsUnion(typeOfX) && (box x) = null then 
    printfn "Static type is %s, but the value is 'null'" typeOfX.Name
  else 
    printfn "Static type is %s and value is not 'null'" typeOfX.Name

答案 1 :(得分:3)

编辑: 不需要代码报价,可以使用typeof,请参阅@Tomas Petricek的回答

您可以使用代码报价从无

中获取类型
open Microsoft.FSharp.Reflection

let printType x = 
    let typeOfX = <@ x @>.Type

    if not <| FSharpType.IsUnion(typeOfX) && (box x) = null then 
        printfn "the type is 'null'"
    else 
        printfn "the type is %A" typeOfX

您的意见:

printType 3          // the type is System.Int32
printType (Some(3))  // the type is Microsoft.FSharp.Core.FSharpOption`1[System.Int32]
printType None       // the type is Microsoft.FSharp.Core.FSharpOption`1[System.Object]
printType null       // the type is 'null'

答案 2 :(得分:0)

这在实现解释器时可能是一个常见问题。要添加到上述解决方案,您还可以执行以下操作:

open System

type TagObj (obj : obj, t : Type) =
    member __.Obj = obj
    member __.Type = t

and TagObj<'T>(value : 'T) =
    inherit TagObj(value, typeof<'T>)

    member __.Value = value
    override __.ToString() = sprintf "%O" value

let mkTag x = TagObj<_>(x) :> TagObj

// examples

let t = mkTag (None : int option)
let t' = mkTag ()

t.Obj = t'.Obj // true
t.Type = t'.Type // false

这大致是如何在引文中表示常量值。