10

F# の識別共用体は抽象クラスにコンパイルされ、そのオプションは入れ子になった具象クラスになります。

type DU = A | B

DU は抽象的ですが、DU.A と DU.B は具体的です。

ServiceStack を使用すると、型の JSON 文字列へのシリアル化とその逆のシリアル化を関数でカスタマイズできます。DU 型に関しては、C# で行う方法を次に示します。

using ServiceStack.Text;

JsConfig<DU.A>.SerializeFn = v => "A"; // Func<DU.A, String>
JsConfig<DU.B>.SerializeFn = v => "B"; // Func<DU.B, String>
JsConfig<DU>.DeserializeFn = s =>
    if s == "A" then DU.NewA() else DU.NewB(); // Func<String, DU>

F# は、識別された共用体のコンパイル済みフォームを認識していますか? コンパイル時に F# で DU.A の型を取得するにはどうすればよいですか?

typeof<DU> // compiles
typeof<DU.A> // error FS0039: The type 'A' is not defined
typeof<A> // error FS0039: The type 'A' is not defined

F# で逆シリアル化する関数を簡単に登録できます。

open System
open ServiceStack.Text

JsConfig<DU>.RawDeserializeFn <-
    Func<_, _>(fun s -> printfn "Hooked"; if s = "A" then A else B)

具体的な型 DU.A および DU.B のシリアル化関数を完全に F# に登録することは可能ですか?

4

3 に答える 3

10

すべての動作 (抽象クラスなど) は単なる実装の詳細ではなく、実際には仕様によって定義されていますが、これらのものは F# からアクセスできません - これは仕様からの引用です

コンパイルされた共用体型 U には次のものがあります。

· 各ヌル ユニオン ケース C に対して 1 つの CLI 静的ゲッター プロパティ UC。このプロパティは、そのような各ケースを表すシングルトン オブジェクトを取得します。

· null 以外のユニオン ケースごとに 1 つの CLI ネスト型 UC。ただし、ケースが 1 つしかないコンパイル済み共用体型には、ネストされた型はありません。代わりに、ユニオン型自体がケース型の役割を果たします。

· null 以外のユニオン ケース C ごとに 1 つの CLI 静的メソッド U.NewC。このメソッドは、そのケースのオブジェクトを構築します。

· ケース C ごとに 1 つの CLI インスタンス プロパティ U.IsC。このプロパティは、ケースに対して true または false を返します。

· ケース C ごとに 1 つの CLI インスタンス プロパティ U.Tag。このプロパティは、ケースに対応する整数タグを取得または計算します。

· U に複数のケースがある場合、1 つの CLI ネスト型 U.Tags があります。U.Tags 型には、ケースごとに 1 つの整数リテラルが含まれており、ゼロから昇順になっています。

· コンパイル済み共用体型には、ユーザー定義のプロパティまたはメソッドに加えて、自動生成されたインターフェイスを実装するために必要なメソッドがあります。

これらのメソッドとプロパティは、F# から直接使用することはできません。ただし、これらの型には、ユーザー向けの List.Empty、List.Cons、Option.None、および Option.Some のプロパティやメソッドがあります。

重要なのは、「これらのメソッドとプロパティは F# から使用できない可能性がある」ということです。

于 2013-07-24T11:51:06.473 に答える
6

ダニエルは正しいです。これを行うには、基本型のシリアル化関数を登録しますDU。これはより完全な例です

open System
open ServiceStack.Text

type DU = A | B

let serialize = function
    | A -> "A"
    | B -> "B"

let deserialize = function
    | "A" -> A
    | "B" -> B
    | _   -> failwith "Can't deserialize"

JsConfig<DU>.SerializeFn <- Func<_,_>(serialize)
JsConfig<DU>.DeSerializeFn <- Func<_,_>(deserialize)

let value = [| A; B |]
let text = JsonSerializer.SerializeToString(value)
let newValue = JsonSerializer.DeserializeFromString<DU[]>(text)

結果:

val value : DU [] = [|A; B|]
val text : string = "["A","B"]"
val newValue : DU [] = [|A; B|]
于 2013-07-24T16:18:39.953 に答える
5

F# の DU が単一の型であるという事実は、その有用性の鍵です。F# のアプローチでは、パターン マッチングを使用します。

JsConfig<DU>.SerializeFn <- function
  | A -> "A"
  | B -> "B"

ユニオン ケースは C# のネストされた型であるだけでなく、サブタイプでもあるため、これは機能するはずです。もちろん、ServiceStack が基本型シリアライザーを考慮しない場合、これは機能しません。

于 2013-07-24T14:16:23.117 に答える