let Construct<'T> (caseInfo: Microsoft.FSharp.Reflection.UnionCaseInfo) =
Microsoft.FSharp.Reflection.FSharpValue.MakeUnion(caseInfo, [||]) :?> 'T
let GetUnionCaseInfoAndInstance<'T> (caseInfo: Microsoft.FSharp.Reflection.UnionCaseInfo) =
(Construct<'T> caseInfo)
let GetAllElementsFromDiscriminatedUnion<'T>() =
Microsoft.FSharp.Reflection.FSharpType.GetUnionCases(typeof<'T>)
|> Seq.map GetUnionCaseInfoAndInstance<'T>
[<JsonConverter(typeof<MyStringTypeConverter>)>]
type DiscUnion =
| D1
| D2
override self.ToString() =
sprintf "%A" self
static member GetAll(): seq<DiscUnion> =
GetAllElementsFromDiscriminatedUnion<DiscUnion>()
and private MyStringTypeConverter() =
inherit JsonConverter()
override this.CanConvert(objectType): bool =
objectType = typedefof<DiscUnion>
override this.ReadJson(reader: JsonReader, objectType: Type, existingValue: Object, serializer: JsonSerializer) =
if (reader.TokenType = JsonToken.Null) then
null
else
let token =
Newtonsoft.Json.Linq.JToken.Load(reader)
// not sure about the below way to convert to string, in stackoverflow it was a C# cast
.ToString()
try
DiscUnion.GetAll().First(fun discUnion -> discUnion.ToString() = token) :> Object
with ex -> raise(new Exception(sprintf "DiscUnion case not found: %s" token, ex))
override this.WriteJson(writer: JsonWriter, value: Object, serializer: JsonSerializer) =
let discUnion = value :?> DiscUnion
writer.WriteValue(discUnion.ToString())
type Foo =
{
Bar: int;
Baz: Map<DiscUnion,int>;
}
Source/destination JSON
{ "Bar": 42, "Baz":{"D1": 4242, "D2": 424242 }}
Expected behavior
Deserialize JSON properly into Foo object (like it would do if I had used TypeConverter instead of JsonConverter).
Actual behavior
Exception:
----> Newtonsoft.Json.JsonSerializationException : Could not convert string 'D1' to dictionary key type 'FSharpTests.Deserialization+DiscUnion'. Create a TypeConverter to convert from the string to the key type object. Path 'Value.Baz.D1', line 1, position 82. ----> Newtonsoft.Json.JsonSerializationException : Error converting value "D1" to type 'FSharpTests.Deserialization+DiscUnion'. Path 'Value.Baz.D1', line 1, position 82.
Source/destination types
Source/destination JSON
Expected behavior
Deserialize JSON properly into Foo object (like it would do if I had used TypeConverter instead of JsonConverter).
Actual behavior
Exception:
Steps to reproduce