2

Le scénario est la suivante: - réception d'une chaîne JSON du réseau et désérialisation du type d'enregistrement correspondant.F # désérialisation d'une chaîne JSON dans le type d'enregistrement correct

chaîne JSON peut être:

(1) "{"a":"some text"}" ou

(2) "{"b":1}"

Les valeurs peuvent différer, mais le format des champs seront soit correspondant à Type1 ou Type2:

type Type1 = {a:string} 
type Type2 = {b:int} 

Lors de la réception d'une chaîne inconnue, j'essaie d'obtenir une instance d'un type d'enregistrement correct:

// Contents of a string might be like (1) or like (2), but we don't know which one 
let someJsonString = "..." 

let obj = JsonConvert.DeserializeObject(someJsonString) 

La dernière ligne renvoie un objet de type Object.

en utilisant la correspondance de motif sur elle ne détermine pas le type:

match obj with 
| :? Type1 as t1 -> printfn "Type1: a = %A" t1.a 
| :? Type2 as t2 -> printfn "Type2: b = %A" t2.b 
| _ -> printfn "None of above" 

Ici, le « Aucun haut » est imprimé.

Quand je désérialiser un objet à l'aide indiquant un certain type:

JsonConvert.DeserializeObject<Type1>(someJsonString) 

Correspondance de modèle fonctionne et impression:

Type1: a = <the value of a> 

Cependant, cela ne fonctionne pas dans mon cas, parce que je peux » Je ne sais pas à l'avance quel type de contenu la chaîne JSON inconnue va avoir.

Est-il possible de désérialiser une chaîne JSON dans le type d'enregistrement correct en fonction du contenu de la chaîne?

Remarque: Si nécessaire, lorsque la chaîne est sérialisée sur le côté où elle est envoyée, le nom du type peut être envoyé en tant que partie de cette chaîne. Mais alors, comment obtenir une instance d'un type Type, ayant un nom d'un type, comme "Type1" ou "Type2"?

Le nom complet du type sera différent sur des machines différentes, donc je ne suis pas sûr que ce soit possible. C'est à dire. une machine aura Type1 spécifié comme:

"FSI_0059+Test1, FSI-ASSEMBLY, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" 

Et comme un autre:

"FSI_0047+Test1, FSI-ASSEMBLY, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" 

Répondre

2

Vous ne pouvez pas le faire sans génériquement informations de type supplémentaire. Le type doit être spécifié lors de la sérialisation, de sorte qu'il puisse être relu lors de la désérialisation.

Newtonsoft.Json a TypeNameHandlingoption that you can set lors de la sérialisation, de sorte que le résultat JSON désérialisé dans le type correct.

Voici un exemple complet:

let instance = { a = 10 } 
let settings = new JsonSerializerSettings(TypeNameHandling = TypeNameHandling.All) 
let json = JsonConvert.SerializeObject(instance, settings) 
let retrieved = JsonConvert.DeserializeObject(json, settings) 
+0

Cela ne fonctionnerait pas si l'objet est sérialisé sur une machine, et désérialisée sur un autre.Par exemple, je l'ai essayé sur une machine - il peut désérialiser un objet à un type correct. Mais si vous le désérialisez sur une machine différente, le nom de type complet est différent pour le type, car il est préfixé avec différentes variantes de "FSI_0047 + Type1" par exemple. Savez-vous comment vous assurer que le même type a le même nom d'assemblage qualifié à chaque exécution? – experimenter

+1

C'est parce que vous utilisez FSI. Les noms de types sont générés. Sinon, partagez un assembly entre les deux machines et référencez-le avec '# r'. – Asti

+0

Merci, je pense que cela fonctionnera – experimenter