差別された組合のタイプ間の変換
-
24-10-2019 - |
質問
さまざまなタイプを返すことができる関数があり、使用します 差別された組合 このため。私が必要とするのは、差別された連合のあるタイプから別のタイプに変換することです。また、一部のタイプは他のすべてのタイプに変換可能です(弦)、しかし、いくつかのタイプは文字列にのみ変換できます(mycustomtype)
このために、メンバーメソッドを追加しました に変換 に ResultType
:
type MyTypes =
| Boolean = 1
| Integer = 2
| Decimal = 3
| Double = 4
| String = 5
| MyCustomType = 6
type ResultType =
| Boolean of bool
| Integer of int
| Decimal of decimal
| Double of double
| String of string
| MyCustomType of MyCustomType
with
member this.ConvertTo(newType: MyTypes) =
match this with
| ResultType.Boolean(value) ->
match newType with
| MyTypes.Boolean ->
this
| MyTypes.Integer ->
ResultType.Integer(if value then 1 else 0)
...
| ResultType.MyCustomType(value) ->
match newType with
| MyTypes.MyCustomType ->
this
| MyTypes.String ->
ResultType.String(value.ToString())
| _ ->
failwithf "Conversion from MyCustomType to %s is not supported" (newType.ToString())
私はそのような構造が好きではありません。なぜなら、私がより多くのタイプを追加すると、これには多くの変更を行う必要があるからです。 myTypes, resultType また、いくつかの場所で に変換 メンバー関数。
誰かがそのようなタイプの変換のためのより良い解決策を提案できますか?
前もって感謝します
解決
わずかに異なるデザインでは、悪用することが可能です System.Convert.ChangeType
そして、差別された組合の建設業者が実際に機能しているという事実:
// statically typed wrapper for System.Convert.ChangeType
let conv a : 'T = System.Convert.ChangeType(a, typeof<'T>) :?> 'T
type MyCustomType() = class end
type ResultType =
| Boolean of bool
| Integer of int
| Decimal of decimal
| Double of double
| String of string
| MyCustomType of MyCustomType
with
member this.ConvertTo (newType:'T->ResultType) =
match this with
| Boolean b -> newType( conv b )
| Integer i -> newType( conv i )
| Decimal d -> newType( conv d )
| Double d -> newType( conv d )
| String s -> newType( conv s )
| MyCustomType m ->
if typeof<'T> <> typeof<string> then
raise (new System.InvalidCastException("MyCustomType can only be converted to String"))
else
String (m.ToString())
let i = Integer 42
let b = i.ConvertTo Boolean
printfn "%A" b
let d = i.ConvertTo Decimal
printfn "%A" d
let d2 = i.ConvertTo Double
printfn "%A" d2
let s = i.ConvertTo String
printfn "%A" s
//let mi = i.ConvertTo MyCustomType // throws InvalidCastException
let m = MyCustomType (new MyCustomType())
let sm = m.ConvertTo String
printfn "%A" sm
//let im = m.ConvertTo Integer // throws InvalidCastException
編集:カスタムタイプを追加すると、これはあまり役に立ちません。
たぶん、カスタムタイプを実装する必要があります IConvertible
. 。その後、特別なケースコードを削除できます ConvertTo
完全に依存しています System.Convert.ChangeType
.
あなたはまだすべてのカスタムタイプを拡張する必要があります ToObject
新しいカスタムタイプを追加するたびに実装。それが本当に中心よりも優れているかどうか ConvertTo
機能は議論の余地があります。
他のヒント
なぜあなたは最初にタイプ変換をしたいのですか?差別された組合は、それを必要とし、抽象的な複雑さを解くまで、タイプ情報を隠す良い方法です。通常、このタイプを消費する関数に一致ステートメントがあり、必要に応じてキャストするだけです。
何らかのタイプのパーサーまたは言語エンジンを作成しようとしている場合は、すべてのキャストまたは少なくともエラー状態を定義する以外に選択肢がありません。なぜこれを使用するのかを詳しく説明しても構わない場合は、別のアプローチを提案できるかもしれません。
余分な:F#と.NETは一般に、返品タイプの過負荷をサポートしていません。