Use of typeof<_> in active pattern
Given the following contrived active pattern:
let (|TypeDef|_|) (typeDef:Type) (value:obj) =
if obj.ReferenceEquals(value, null) then 开发者_StackOverflow社区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?
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
| _ -> ()
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
| _ -> ()
精彩评论