Как десериализовать JSON для правильного типа, используя F#
Я новичок в F# и функциональном программировании.
У меня есть эти два типа
type User= {
active: bool
funds: int
}
and UserDto = {
user: User
}
type Transaction = {
amount: int
time: DateTime
}
and TransactionDto = {
transaction: Transaction
}
И я должен взять некоторую строку JSON в качестве ввода, и это может быть User
или же Transaction
Я пытаюсь с Fsharp.Json
и это прекрасно работает, если я знаю тип.
let getUserInput =
let input = System.Console.ReadLine()
let acc = Json.deserialize<Account> input
printfn "%A" acc
Есть ли способ сделать это без проверки, если входная строка содержит account
сделать эту сериализацию иначе, если входная строка содержит transaction
делать другой?
[РЕДАКТИРОВАТЬ]
Как вы, ребята, сказали, я, как сказал Девон Буррисс, но использовал другой подход. Следует за функцией
let getOperation json =
let j = JObject.Parse json
match j.Properties().Select(fun p -> p.Name).FirstOrDefault() with
| "account" -> AccountOperation(JsonConvert.DeserializeObject<AccountDto>(json))
| "transaction" -> TransactionOperation(JsonConvert.DeserializeObject<TransactionDto>(json))
| _ -> InvalidOperation "invalid-operation"
1 ответ
Как уже указывалось, вам нужно знать тип для десериализации этого типа.
Если по какой-то причине вы не знаете тип входящего и не можете контролировать клиента, я отправлю дополнительную информацию. Имя типа или поскольку вы используете F#, сериализуйте тип суммы следующим образом:
type Dto =
| UserType of User
| UserDtoType of UserDto
| TransactionType of Transaction
| TransactionDtoType of TransactionDto
Теперь вы можете десериализовать в Dto
и образец совпадения оттуда.
match v with
| UserType x -> printfn "I am a User %A" x
| UserDtoType x -> printfn "I am a UserDto %A" x
| TransactionType x -> printfn "I am a Transaction %A" x
| TransactionDtoType x -> printfn "I am a TransactionDto %A" x
Я знаю, что вы упомянули НЕ проверять свойства, но я хотел указать на тип суммы, если вы пойдете по этому пути.
Если вы не можете изменить клиента для отправки дополнительной информации, вы можете проверить JSON и перейти к типу суммы при десериализации, но это вполне вручную и подвержено ошибкам, но я не вижу другого пути. Можно, конечно, сделать это красивее, но это должно продемонстрировать, что я имею в виду.
let serialize x = JsonConvert.SerializeObject(x)
let deserialize json =
let jObj = JObject.Parse(json)
if(jObj.ContainsKey("active")) then Dto.UserType (jObj.ToObject<User>())
elif(jObj.ContainsKey("user")) then Dto.UserDtoType (jObj.ToObject<UserDto>())
elif(jObj.ContainsKey("amount")) then Dto.TransactionType (jObj.ToObject<Transaction>())
elif(jObj.ContainsKey("transaction")) then Dto.TransactionDtoType (jObj.ToObject<TransactionDto>())
else failwith "Unknown type"
Примечание: это использует Newtonsoft исключительно потому, что я знаю, что он имеет нижний уровень JObject и не знаком ни с каким нижним уровнем
FSharp.Json
функции.