Use of typeof<_> in active pattern

时光怂恿深爱的人放手 提交于 2019-12-23 10:34:07

问题


Given the following contrived active pattern:

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

The following:

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

gives the error:

Unexpected type application in pattern matching. Expected '->' or other token.

But this works:

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

Why is typedefof (or typeof) not allowed here?


回答1:


Even if you're using a parameterized active pattern (where the argument is some expression), the compiler parses the argument as a pattern (as opposed to an expression), so the syntax is more restricted.

I think this is essentially the same problem as the one discussed here: How can I pass complex expression to parametrized active pattern? (I'm not sure about the actual compiler implementation, but the F# specification says that it should parse as a pattern).

As a workaround, you can write any expression inside a quotation, so you could do this:

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
| _ -> ()



回答2:


Adding to Tomas' answer, the troublesome syntax in this case appears to be with the explicit type arguments. Another workaround is to use a dummy parameter to transmit the type information

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
    | _ -> ()


来源:https://stackoverflow.com/questions/6779602/use-of-typeof-in-active-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!