我有一个包含水果列表的字符串。我的C#程序不能直接使用Fruit,它需要将它们转换为Banana或Apple。有关投射内容的信息包含在json中的constructor
属性中。
注意:我使用的是JSON.NET。
这就是我想要实现的目标:
class Fruit{ public string constructor;}
class Banana : Fruit { public int monkey;}
class Apple : Fruit { public string shape;}
string json = @"[
{
""constructor"":""banana"",
""monkey"":1
},
{
""constructor"":""apple"",
""shape"":""round""
}]";
List<Fruit> fruitList = JsonConvert.DeserializeObject<List<Fruit>>(json);
List<Banana> bananaList = new List<Banana>();
List<Apple> appleList = new List<Apple>();
foreach(var fruit in fruitList){
if(fruit.constructor == "banana") bananaList.Add((Banana)fruit); //bug
if(fruit.constructor == "apple") appleList.Add((Apple)fruit); //bug
}
//use bananaList and appleList for stuff
但是,我无法进行演员表演。有没有办法使bananaList包含json中的所有对象,其构造函数属性设置为"banana"
,对于appleList是否相同?
解决方案:
public static string objToJson(object obj) {
return JsonConvert.SerializeObject(obj, Formatting.Indented, new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.Auto
});
}
public static T jsonToObj<T>(string str) {
return JsonConvert.DeserializeObject<T>(str, new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.Auto
});
}
答案 0 :(得分:1)
在JSON.Net中,您可以使用$type
来指定要反序列化的类型:
string json = @"[
{
""$type"":""Assembly.Namespace.banana"",
""monkey"":1
},
{
""$type"":""Assembly.Namespace.apple"",
""shape"":""round""
}]";
答案 1 :(得分:1)
您尝试进行多态反序列化,但是您要求反序列化器反序列化为List of Fruit。你无法向播放Apple / Banana,因为实例将是Fruit。
如果您控制了json,则可以在其中保存带有类型信息的json,并且反序列化器将自动创建正确的类型。
public class Fruit{ }
public class Banana : Fruit { public int monkey;}
public class Apple : Fruit { public string shape;}
class Program
{
static void Main(string[] args)
{
var list = new List<Fruit>(new Fruit[] {new Banana(), new Apple()});
var serializerSettings = new JsonSerializerSettings{ TypeNameHandling = TypeNameHandling.Auto };
var json = JsonConvert.SerializeObject(list, serializerSettings);
List<Fruit> fruitList = JsonConvert.DeserializeObject<List<Fruit>>(json, serializerSettings);
List<Banana> bananaList = new List<Banana>();
List<Apple> appleList = new List<Apple>();
foreach (var fruit in fruitList)
{
if (fruit is Banana) bananaList.Add((Banana) fruit);
if (fruit is Apple) appleList.Add((Apple) fruit);
}
}
}
你也可以使用一些linq比foreach更容易找到苹果/香蕉:
List<Banana> bananaList = fruitList.Where(f => f is Banana).Cast<Banana>().ToList();
List<Apple> appleList = fruitList.Where(f => f is Apple).Cast<Apple>().ToList();
或者您可以使用此处讨论的转换器Deserializing polymorphic json classes without type information using json.net
答案 2 :(得分:0)
JSON.NET只能解析它希望解析的内容。它没有办法假设它想要使用的类的多态子。
如果您可以控制源JSON,则可以告诉序列化程序包含有关正在使用的类型的数据。
如果您不这样做,我相信您需要手动(或通过JToken
或类似的)读取数据以找到constructor
属性,然后再告诉它解析正确的属性类型。