在活动模式中使用 typeof<_>



给定以下人为活动模式:

let (|TypeDef|_|) (typeDef:Type) (value:obj) =
  if obj.ReferenceEquals(value, null) then None
  else
    let typ = value.GetType()
    if typ.IsGenericType && typ.GetGenericTypeDefinition() = typeDef then Some(typ.GetGenericArguments())
    else None

:

let dict = System.Collections.Generic.Dictionary<string,obj>()
match dict with
| TypeDef typedefof<Dictionary<_,_>> typeArgs -> printfn "%A" typeArgs
| _ -> ()

给出错误:

模式匹配中意外的类型应用程序。期望'->'或其他标记。

但这是有效的:

let typ = typedefof<Dictionary<_,_>>
match dict with
| TypeDef typ typeArgs -> printfn "%A" typeArgs
| _ -> ()

为什么这里不允许使用typedefof(或typeof) ?

即使使用参数化的活动模式(其中参数是某个表达式),编译器也会将参数解析为模式(而不是表达式),因此语法更受限制。

我认为这本质上与这里讨论的问题相同:我如何将复杂表达式传递给参数化活动模式?(我不确定实际的编译器实现,但f#规范说它应该作为模式解析)。

作为一种变通方法,您可以在引号内编写任何表达式,因此您可以这样做:
let undef<'T> : 'T = Unchecked.defaultof<_>
let (|TypeDef|) (typeExpr:Expr) (value:obj) =
  let typeDef = typeExpr.Type.GetGenericTypeDefinition()
  // ...
let dict = System.Collections.Generic.Dictionary<string,obj>()
match dict with
| TypeDef <@ undef<Dictionary<_,_>> @> typeArgs -> printfn "%A" typeArgs
| _ -> ()

加上Tomas的回答,在这种情况下,麻烦的语法似乎与显式类型参数有关。另一个解决方法是使用一个虚拟参数来传输类型信息

let (|TypeDef|_|) (_:'a) (value:obj) =
  let typeDef = typedefof<'a>
  if obj.ReferenceEquals(value, null) then None
  else
    let typ = value.GetType()
    if typ.IsGenericType && typ.GetGenericTypeDefinition() = typeDef then Some(typ.GetGenericArguments())
    else None
let z = 
    let dict = System.Collections.Generic.Dictionary<string,obj>()
    match dict with
    | TypeDef (null:Dictionary<_,_>) typeArgs -> printfn "%A" typeArgs
    | _ -> ()

相关内容

  • 没有找到相关文章

最新更新