Десериализовать JSON на основе полей в.Net (C#)
Я пишу приложение, которое получает Json
список объектов вроде этого:
[
{
"ObjectType": "apple",
"ObjectSize": 35,
"ObjectCost": 4,
"ObjectTaste": "good",
"ObjectColor": "golden"
},
{
"ObjectType": "books",
"ObjectSize": 53,
"ObjectCost": 7,
"Pages": 100
},
{
"ObjectType": "melon",
"ObjectSize": 35,
"ObjectTaste": "good",
"ObjectCost": 5
},
{
"ObjectType": "apple",
"ObjectSize": 29,
"ObjectCost": 8,
"ObjectTaste": "almost good",
"ObjectColor": "red"
}
]
Я хочу сделать базовый класс ItemToSell
(размер, стоимость), и извлечь из него Apple, дыни и книги, а затем сделать десериализацию на основе "ObjectType
"поле для любого класса, который он подходит. Я хочу, чтобы он составил список ItemToSell
объекты, каждый объект Яблоко, Дыня или Книга.
Как я мог сделать это в.Net?
Заранее спасибо:)
РЕДАКТИРОВАТЬ: Я знаю, как десериализовать его в большом классе со всеми полями, которые он может когда-либо содержать, например: Base(ObjectType,ObjectSize,ObjectCost,ObjectColor,Pages)
, Но я хочу, чтобы он различал классы по ObjectType
поэтому у меня не будет никаких полезных полей, таких как поле Страницы для каждого элемента книги или ObjectTaste
за каждую книгу.
6 ответов
Некоторое время назад у меня была такая же проблема.
Вы можете использовать Json.NET, но если у вас нет контроля над документом json (как в: "он был сериализован каким-то другим фреймворком"), вам нужно создать собственный JsonConverter, например так:
class MyItemConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(ItemToSell).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject obj = JObject.Load(reader);
string discriminator = (string)obj["ObjectType"];
ItemToSell item;
switch (discriminator)
{
case "apple":
item = new Apple();
break;
case "books":
item = new Books();
break;
case "melon":
item = new Melon();
break;
default:
throw new NotImplementedException();
}
serializer.Populate(obj.CreateReader(), item);
return item;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
}
}
Затем вам нужно добавить его в конвертеры JsonSerializerSettings следующим образом:
JsonSerializerSettings settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
};
settings.Converters.Add(new MyItemConverter());
var items = JsonConvert.DeserializeObject<List<ItemToSell>>(response, settings);
Вы можете использовать CustomCreationConverter. Это позволяет вам подключиться к процессу десериализации.
public abstract class Base
{
public string Type { get; set; }
}
class Foo : Base
{
public string FooProperty { get; set; }
}
class Bar : Base
{
public string BarProperty { get; set; }
}
class CustomSerializableConverter : CustomCreationConverter<Base>
{
public override Base Create(Type objectType)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
var type = (string)jObject.Property("Type");
Base target;
switch (type)
{
case "Foo":
target = new Foo();
break;
case "Bar":
target = new Bar();
break;
default:
throw new InvalidOperationException();
}
serializer.Populate(jObject.CreateReader(), target);
return target;
}
}
class Program
{
static void Main(string[] args)
{
var json = "[{Type:\"Foo\",FooProperty:\"A\"},{Type:\"Bar\",BarProperty:\"B\"}]";
List<Base> bases = JsonConvert.DeserializeObject<List<Base>>(json, new CustomSerializableConverter());
}
}
Это не ответ, но в C# 6.0 вы сможете сделать это:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json.Linq;
[TestMethod]
public void JsonWithDollarOperatorStringIndexers()
{
// Additional data types eliminated for elucidation
string jsonText = @"
{
'Byte': {
'Keyword': 'byte',
'DotNetClassName': 'Byte',
'Description': 'Unsigned integer',
'Width': '8',
'Range': '0 to 255'
},
'Boolean': {
'Keyword': 'bool',
'DotNetClassName': 'Boolean',
'Description': 'Logical Boolean type',
'Width': '8',
'Range': 'True or false.'
},
}";
JObject jObject = JObject.Parse(jsonText);
Assert.AreEqual("bool", jObject.$Boolean.$Keyword);
}
Взято отсюда.
Определите базовый класс и производные классы.
использование [JSON.net](также доступно через NuGet) 1 для десериализации их.
Т.е.
class ItemToSell {
string Type {get;set;}
string Size {get;set;}
string Cost {get;set;}
}
class Book : ItemToSell { ...}
Затем десериализовать с помощью
var catalog = JsonConvert.Deserialize<List<ItemToSell>>(json);
Десериализатор будет игнорировать неожиданные свойства. Вызовите его снова, используя определенный тип, чтобы получить другие свойства, если вам нужно.
Твой класс:
public class RootObject
{
public string ObjectType { get; set; }
public int ObjectSize { get; set; }
public int ObjectCost { get; set; }
public string ObjectTaste { get; set; }
public string ObjectColor { get; set; }
public int? Pages { get; set; }
}
Десериализовать с помощью библиотеки NewtonSoft JSON следующим образом:
var Jsonobject = JsonConvert.DeserializeObject<RootObject>(json);
Взгляните на библиотеку JSON от Newtonsoft
С его помощью вы можете делать такие вещи, как:
...
public class Movie
{
public string Name;
public DateTime ReleaseDate;
public string[] Genres;
}
......
string json = @"{
'Name': 'Bad Boys',
'ReleaseDate': '1995-4-7T00:00:00',
'Genres': [
'Action',
'Comedy'
]
}";
Movie m = JsonConvert.DeserializeObject<Movie>(json);
string name = m.Name;
// Bad Boys