5

次の工夫されたアクティブ パターンが与えられます。

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) がここで許可されていないのはなぜですか?

4

2 に答える 2

5

パラメーター化されたアクティブ パターン (引数が式である) を使用している場合でも、コンパイラは引数を (式ではなく) パターンとして解析するため、構文はより制限されます。

これは、ここで説明した問題と本質的に同じ問題だと思います: How can I pass complex expression to parameterized 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
| _ -> ()
于 2011-07-21T17:45:34.320 に答える
5

トーマスの答えに加えて、この場合の厄介な構文は、明示的な型引数を使用しているようです。別の回避策は、ダミー パラメータを使用して型情報を送信することです。

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
    | _ -> ()
于 2011-07-21T18:37:37.037 に答える