【问题标题】:How to achieve ideal json serializing/deserializing in C# UWP?如何在 C# UWP 中实现理想的 json 序列化/反序列化?
【发布时间】:2016-05-19 03:55:32
【问题描述】:

注意:问题仅限于 C# UWP

梦想:

public static class Serializer {
    // return json string
    public string Serialize(object obj) { ??? }
    // return T from json string
    public T Deserialize<T>(string jsonString) { ??? }
}

最近的一次:

public static class Serializer
{
    public static string Serialize(object obj, DataContractJsonSerializerSettings settings=null)
    {
        if (obj == null) {
            throw new NullReferenceException();
        }

        settings = settings ?? new DataContractJsonSerializerSettings();
        DataContractJsonSerializer jsonizer = new DataContractJsonSerializer(obj.GetType(), settings);
        string jsonString = null;
        using ( MemoryStream stream = new MemoryStream() )
        {
            jsonizer.WriteObject(stream, obj);
            stream.Position = 0;
            StreamReader sr = new StreamReader(stream);
            jsonString = sr.ReadToEnd();
        }
        return jsonString;
    }

    public static T Deserialize<T>(string jsonString)
    {
        DataContractJsonSerializer jsonizer = new DataContractJsonSerializer(typeof(T));
        T obj;
        using (Stream stream = GenerateStreamFromString(jsonString))
        {
            obj = (T)jsonizer.ReadObject(stream);
        }
        return obj;
    }

    private static Stream GenerateStreamFromString(string s)
    {
        MemoryStream stream = new MemoryStream();
        StreamWriter writer = new StreamWriter(stream);
        writer.Write(s);
        writer.Flush();
        stream.Position = 0;
        return stream;
    }
}

问题

我发布的部分解决方案适用于简单的情况。但是,当被反序列化的对象的子类型很难(或不可能)从 json 字符串中确定时,它会失败。例如,

IList<Animal> animals = new List<Animal>();
animals.add(new Dog("Woofy"));
animals.add(new Cat("Fluffy"));

string json = Serializer.Serialize(animals);
IList<Animal> result = Serializer.Deserialize<List<Animal>>(json);
// ^ fails because subtype information was lost during serialization

bool succeeded = result.get(0).Name.Equals("Woofy") && result.get(1).Name.Equals("Fluffy");

我在寻找什么:

“梦想”中指定的骨架的实现,它通过“问题”中指定的驱动程序。欢迎评论。

【问题讨论】:

标签: c# json serialization


【解决方案1】:

如果您将KnownType-attributes 添加到您的基类中,您的序列化程序可以正常工作:

[DataContract]
[KnownType(typeof(Dog))] // add these
[KnownType(typeof(Cat))] // lines
public class Animal
{
    [DataMember]
    public string Name { get; set; }
}

[DataContract]
public class Dog : Animal
{
}

[DataContract]
public class Cat : Animal
{
}

DataContractJsonSerializer 必须保留正在序列化的实例的类型信息。您可以在生成的序列化 JSON 中看到这一点:

[{\"__type\":\"Dog:#My.Serialization.Sample.Project\",\"Name\":\"Woofy\"},{\"__type\":\"Cat:#My.Serialization.Sample.Project\",\"Name\":\"Fluffy\"}]

还有一个额外的键__type,它保存了第一个对象是Dog表单命名空间My.Serialization.Sample.Project的具体信息。


但是正如@dbc 已经提到的,使用 JSON.NET 可能会稍微好一些,它可以轻松地序列化列表,而无需使用所有这些属性来装饰数据传输对象。甚至不需要DataContractDataMember

public class Animal
{
    public string Name { get; set; }
}

public class Dog : Animal { }

public class Cat : Animal { }

以这种方式使用它

var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
string jsonNet = JsonConvert.SerializeObject(animals, settings);
var jsonNetResult = JsonConvert.DeserializeObject<IList<Animal>>(jsonNet);

产生的结果:

[{\"$type\":\"My.Serialization.Sample.Project.Dog, My.Assembly\",\"Name\":\"Woofy\"},{\"$type\":\"My.Serialization.Sample.Project.Cat, My.Assembly\",\"Name\":\"Fluffy\"}]

【讨论】:

    【解决方案2】:

    使用JsonSubTypes,您至少有两种可能性:

    [JsonConverter(typeof(JsonSubtypes))]
    [JsonSubtypes.KnownSubTypeWithProperty(typeof(Dog), "HadWalkToday")]
    [JsonSubtypes.KnownSubTypeWithProperty(typeof(Cat), "ColorOfWhiskers")]
    public class Animal
    {
        public string Name { get; set; }
    }
    
    public class Dog : Animal
    {
        public bool HadWalkToday { get; set; }
    }
    
    public class Cat : Animal
    {
        public string ColorOfWhiskers { get; set; }
    }
    

    [JsonConverter(typeof(JsonSubtypes), "Sound")]
    [JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
    [JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
    public class Animal
    {
        public virtual string Sound { get; }
        public string Color { get; set; }
    }
    
    public class Dog : Animal
    {
        public override string Sound { get; } = "Bark";
        public string Breed { get; set; }
    }
    
    public class Cat : Animal
    {
        public override string Sound { get; } = "Meow";
        public bool Declawed { get; set; }
    }
    

    适用于:

    [Test]
    public void Proof()
    {
        Dog dog = new Dog()
        {
            Name = "Woofy",
            HadWalkToday = true
        };
        Cat cat = new Cat()
        {
            Name = "Fluffy",
            ColorOfWhiskers = "Brown"
        };
        IList<Animal> animals = new List<Animal>()
        {
            dog,
            cat
        };
    
        string json = JsonConvert.SerializeObject(animals);
        IList<Animal> result = JsonConvert.DeserializeObject<List<Animal>>(json);
    
        Assert.IsTrue(result[0].GetType() == typeof(Dog));
        Assert.IsTrue(result[1].GetType() == typeof(Cat));
    }
    

    【讨论】:

      【解决方案3】:

      我得到的答案:

      using System;
      using System.Collections.Generic;
      using Newtonsoft.Json;
      
      namespace SerializationDemo
      {
          class Program
          {
              static void Main(string[] args)
              {
                  Dog dog = new Dog()
                  {
                      Name = "Woofy",
                      HadWalkToday = true
                  };
                  Cat cat = new Cat()
                  {
                      Name = "Fluffy",
                      ColorOfWhiskers = "Brown"
                  };
                  IList<Animal> animals = new List<Animal>()
                  {
                      dog,
                      cat
                  };
      
                  string json = Serializer.Serialize(animals);
                  IList<Animal> result = Serializer.Deserialize<List<Animal>>(json);
      
                  bool serializerSuccessful = dog.Equals(result[0]) && cat.Equals(result[1]);
              }
          }
      
          public class Animal
          {
              public string Name { get; set; }
      
              public override bool Equals(object obj)
              {
                  var animal = obj as Animal;
                  return this.Name == animal.Name;
              }
          }
      
          public class Dog : Animal
          {
              public bool HadWalkToday { get; set; }
      
              public override bool Equals(object obj)
              {
                  var dog = obj as Dog;
                  return this.HadWalkToday == dog.HadWalkToday && base.Equals(obj);
              }
          }
      
          public class Cat : Animal
          {
              public string ColorOfWhiskers { get; set; }
      
              public override bool Equals(object obj)
              {
                  var cat = obj as Cat;
                  return this.ColorOfWhiskers == cat.ColorOfWhiskers && base.Equals(obj);
              }
          }
      
          public static class Serializer
          {
              private static readonly JsonSerializerSettings settings = new JsonSerializerSettings()
              {
                  TypeNameHandling = TypeNameHandling.All,
                  Formatting = Formatting.Indented
              };
      
              public static string Serialize(object obj)
              {
                  if (obj == null)
                  {
                      throw new NullReferenceException();
                  }
      
                  string jsonString = JsonConvert.SerializeObject(obj, settings);
                  return jsonString;
              }
      
              public static T Deserialize<T>(string jsonString)
              {
                  T obj = JsonConvert.DeserializeObject<T>(jsonString, settings);
                  return obj;
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2014-01-06
        • 1970-01-01
        • 2021-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-17
        • 1970-01-01
        相关资源
        最近更新 更多