鉴于以下设计的活跃模式:
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
| _ -> ()
给出错误:
模式匹配中的意外类型应用程序。预期' - &gt;'或其他令牌。
但这有效:
let typ = typedefof<Dictionary<_,_>>
match dict with
| TypeDef typ typeArgs -> printfn "%A" typeArgs
| _ -> ()
为什么不允许typedefof
(或typeof
)?
答案 0 :(得分:4)
即使你使用参数化的活动模式(参数是某个表达式),编译器也会将参数解析为模式(而不是表达式),因此语法更受限制。
我认为这与本文讨论的问题基本相同:How can I pass complex expression to parametrized active pattern?(我不确定实际的编译器实现,但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
| _ -> ()
答案 1 :(得分:4)
添加到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
| _ -> ()