根据JSON属性转换为特定类型

时间:2014-09-05 05:05:55

标签: c# json class json.net

我有一个包含水果列表的字符串。我的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
        });
    }

3 个答案:

答案 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属性,然后再告诉它解析正确的属性类型。