2017-07-21 4 views
3

F#コードの一部の関数は、基になる値が入力されてもオブジェクトとしてボックス化された値を受け取ります。値が識別された共用体の場合、そのF#型に戻すことはできません。ここでは簡単な例である: - Result.OkF#の値をアンボックスすると、ユニオンが識別されます

type Result<'TOk,'TError> = 
| Ok of 'TOk 
| Error of 'TError 

type ResultA = Result<string, int> 

let a = Ok "A" 
let o = box a 

match o with 
| :? ResultA -> printfn "match ResultA" 
// | :? ResultA.Ok -> printfn "match" // doesn't compile 
| _ when o.GetType().DeclaringType = typedefof<ResultA> -> printfn "match via reflection" 
| _ -> printfn "no match" 

この例からの出力は、箱入りの値が異なるCLR型であるため、ResultAが一致したことはありません、「リフレクション経由一致」です。 F#識別された共用体のケースは、それ自身の型として表現されるので、ボックス化された値は型ResultAと一致しません。さらに、F#コード内では合法的な型ではないため、ResultA.OKと一致させることはできません。唯一のオプションは、値がすでにインスタンス化されているため、非効率的で愚かなリフレクションを使用した値の手動インスタンス化のようです。ここでは、F#コードでは一度アクセスできません。

私は何か見落としていますか? F#で識別されたユニオン値をアンボックスするより簡単な方法はありますか?

答えて

4

あなたはちょうど別のタイプにマッチしています。変数aは、ResultAのではなくではありませんが、ボックス化された場合はResult<string, obj>に強制的に変換される汎用タイプResult<string, 'a>です。

いずれかの変数を作るには、明示的に正しい型を持っている:右のタイプと

let a : ResultA = Ok "A" 

またはmatch:

match o with 
| :? Result<string, obj> -> printfn "match ResultA" 

両方のオプションが動作します。


あなたの前提に関する注記:箱入り値が異なるCLR型であるため、

ResultAが一致されることはありません - ないResult.Ok

理由。タイプとのマッチングは、C#のis/asの演算子と同じです。つまり、サブタイプと正確なタイプに一致します。 DUメンバーは、DUタイプそのもののサブタイプとしてコンパイルされます。それはF#が.NETに1つのタイプとして異なるケースを扱えるようにする方法です。

一般でランタイムタイピングに関する注意:実行時に
取り扱いタイプは必要ありません。可能な限り避けてください。経験則は、実行時に型を処理する場合、おそらく間違ったものをモデル化しているはずです。

正確にはすべての仕組みがわからない場合は、特にそうです。

+0

ありがとうFyodor。実際にあなたの最初の提案はうまくいかなかった - 変数を明示的に正しいボックス型にし、一致しなかった変数を作成する。しかし、2番目の方法では、パターンマッチングのケースを変更しました。 –

+0

最初のオプションを試してみるには間違いがあります。それは動作します。 –

+0

あなたの予防措置に私は完全に同意します。残念ながら、私は外部ライブラリの特性のためにいくつかの値を扱わなければなりません。 –

関連する問題