2

Сценарий - получение строки JSON из сети и десериализация ее в правильный соответствующий тип записи.F # десериализовать строку JSON в правильный тип записи

JSON, строка может быть либо:

(1) "{"a":"some text"}" или

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

Значения могут отличаться, но формат полей будет либо соответствующая Type1 или типа 2:

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

При получении неизвестной строки я пытаюсь получить экземпляр правильного типа записи:

// 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) 

Последняя строка возвращает объект типа Object.

Использование сопоставления с образцом на нем не определяет тип:

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" 

Здесь «Ни один из выше» не печатается.

Когда я десериализация объекта с помощью индикации определенного типа:

JsonConvert.DeserializeObject<Type1>(someJsonString) 

соответствия шаблона работает и печать:

Type1: a = <the value of a> 

Однако, это не работает в моем случае, потому что я могу» t заранее знать, какой тип содержимого неизвестен для строки JSON.

Есть ли способ десериализации строки JSON в правильный тип записи на основе содержимого строки?

Примечание: При необходимости, когда строка сериализуется на стороне, на которой она отправляется, имя типа может быть отправлено как часть этой строки. Но тогда, как получить экземпляр типа Type, имеющий имя типа, типа «Type1» или «Type2»?

Полностью квалифицированное имя типа будет отличаться на разных машинах, поэтому я не уверен, что это возможно. То есть одна машина будет Type1 определен как:

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

И еще один, как:

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

ответ

2

Вы не можете сделать это в общем без дополнительной информации типа. Тип должен быть указан при сериализации, чтобы его можно было прочитать при десериализации.

Newtonsoft.Json имеет номер TypeNameHandlingoption that you can set при сериализации, так что полученный JSON десериализуется в правильный тип.

Вот полный пример:

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

Это не будет работать, если объект сериализации на одной машине, и десериализации на другой.Например, я пробовал это на одной машине - он может десериализовать объект на правильный тип. Но если вы десериализуете его на другой машине, полное имя типа отличается от типа, потому что оно имеет префикс с различными вариантами «FSI_0047 + Type1», например. Вы знаете, как убедиться, что у одного и того же типа есть одно и то же полное имя сборки для каждого запуска? – experimenter

+1

Это потому, что вы используете FSI. Создаются имена. В противном случае разделите сборку между двумя машинами и укажите ее с помощью '# r'. – Asti

+0

Спасибо, я думаю, это сработает – experimenter