I'm new with F# and functional programming.
I have these two types
type User= {
active: bool
funds: int
}
and UserDto = {
user: User
}
type Transaction = {
amount: int
time: DateTime
}
and TransactionDto = {
transaction: Transaction
}
And I have to take some JSON string as input and it can be a User
or Transaction
I'm trying with Fsharp.Json
and it works fine if I know the type.
let getUserInput =
let input = System.Console.ReadLine()
let acc = Json.deserialize<Account> input
printfn "%A" acc
Is there a way to do that without verifying if the input string contains account
do this serialization else if the input string contains transaction
do the other?
[EDIT]
As You guys said, I did like Devon Burriss said, but using a different approach. It follows the funcion
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"
As has been pointed out, you need to know the type to deserialize to that type.
If for some reason you do not know the type coming in and have control of the client, I would send extra information. A type name or since you are using F#, serialize a sum type like so:
type Dto =
| UserType of User
| UserDtoType of UserDto
| TransactionType of Transaction
| TransactionDtoType of TransactionDto
Now you can deserialize to Dto
and pattern match from there.
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
I know you specifically mentioned NOT checking the properties but I did want to point out going to a sum type if you do go that route.
If you can not change the client to send more information you could inspect the JSON and go to the sum type when you deserialize but that is quite manual and error-prone but I don't see another way. You could, of course, make this prettier but it should demonstrate what I mean.
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"
Note: This is using Newtonsoft purely because I know it has the lower level JObject and am not familiar with any lower level
FSharp.Json
features.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.