【问题标题】:Benefits and drawbacks of generated C# classes for Json objects为 Json 对象生成 C# 类的优缺点
【发布时间】:2012-03-03 00:11:57
【问题描述】:

我有示例 Json,我需要将其序列化为 C# 对象。我决定为此目的利用Json.Net 库。我还需要有代表这个 Json 的 C# 类。可以使用Json C# class generator 创建类。我们有两个选择。 “创建属性”和生成的类将如下所示:

public class Address
{
    private JObject __jobject;
    public Address(JObject obj)
    {
        this.__jobject = obj;
    }
    public string street_address
    {
        get
        {
            return JsonClassHelper.ReadString(JsonClassHelper.GetJToken<JValue>(__jobject, "street_address"));
        }
    }
    public string city
    {
        get
        {
            return JsonClassHelper.ReadString(JsonClassHelper.GetJToken<JValue>(__jobject, "city"));
        }
    }
    public string state_province
    {
        get
        {
            return JsonClassHelper.ReadString(JsonClassHelper.GetJToken<JValue>(__jobject, "state_province"));
        }
    }
    public string zip_postal_code
    {
        get
        {
            return JsonClassHelper.ReadString(JsonClassHelper.GetJToken<JValue>(__jobject, "zip_postal_code"));
        }
    }
}

另一个选项是“生成预填充的只读字段”,类看起来像

public class Address
{

    public Address(JObject obj)
    {
       this.street_address = JsonClassHelper.ReadString(JsonClassHelper.GetJToken<JValue>(obj, "street_address"));
       this.city = JsonClassHelper.ReadString(JsonClassHelper.GetJToken<JValue>(obj, "city"));
       this.state_province = JsonClassHelper.ReadString(JsonClassHelper.GetJToken<JValue>(obj, "state_province"));
       this.zip_postal_code = JsonClassHelper.ReadString(JsonClassHelper.GetJToken<JValue>(obj, "zip_postal_code"));
    }

    public readonly string street_address;
    public readonly string city;
    public readonly string state_province;
    public readonly string zip_postal_code;
}

这两个生成的类都依赖于 JObject 和 JsonClassHelper。但是这些类不能和 JsonSerializer 一样使用

var ro = jsonSerializer.Deserialize<RootObject>(reader);

我们可以使用 JObject.Load 方法创建这些类的对象

var ro = new RootObject(Newtonsoft.Json.Linq.JObject.Load(reader));

另一种方法是使用在线json2csharp 转换器,类会看起来像

public class Address
{
    public string street_address { get; set; }
    public string city { get; set; }
    public string state_province { get; set; }
    public string zip_postal_code { get; set; }
}

JsonSerializer 可以处理这个类。

我的问题是什么类生成器更适合使用,使用每种类型的生成类有什么好处和缺点?
谢谢你的建议。

【问题讨论】:

    标签: c# asp.net json serialization code-generation


    【解决方案1】:

    我假设您想将 json 字符串反序列化为 c# 对象。我一般自己创建C#对象,使用JsonConvert反序列化json字符串。

    class Program {
            static void Main(string[] args)
            {
                    string json = @"
                    {
                            ""street_address"":""My street address"",
                            ""city"":""My City"",
                            ""state_province"":""My State Province"",
                            ""zip_postal_code"":""My Zip Postal Code"",
                    }";
    
                    Address address = JsonConvert.DeserializeObject<Address>(json);
                    Console.WriteLine("Street address: {0}", address.StreetAddress);
                    Console.WriteLine("City: {0}", address.City);
                    Console.WriteLine("State province: {0}", address.StateProvince);
                    Console.WriteLine("Zip postal code: {0}", address.ZipPostalCode);
            }
    }
    
    public class Address {
            [JsonProperty("street_address")]
            public string StreetAddress { get; set; }
    
            [JsonProperty("city")]
            public string City { get; set; }
    
            [JsonProperty("state_province")]
            public string StateProvince { get; set; }
    
            [JsonProperty("zip_postal_code")]
            public string ZipPostalCode { get; set; }
    }
    

    【讨论】:

      【解决方案2】:

      如果您知道要返回的对象类型,请查看在 4.0 框架中使用 System.Runtime.Serialization.Json 命名空间。它比 JSON.NET 更容易使用。事实上,它可能是最简单的替代方案。

      在包含对该命名空间的引用(以及 using 语句)之后,您需要使用 [DataContract] 属性标记您的类,并使用 标记每个属性>[DataMember] 属性。然后,您可以使用这样的通用例程:

      /// <summary>
      /// 
      /// Generic helper class to convert JSON text to in-memory objects
      /// </summary>
      /// <typeparam name="T">Type of class that the text represents</typeparam>
      public class JSONHandler<T> where T : class, new()
      {
          /// <summary>
          /// Convert a JSON string to an in-memory object of class T.
          /// The class T must be instantiable and not static.
          /// </summary>
          /// <param name="JSONString">JSON string describing the top level object</param>
          /// <returns>Object of class T (and any dependent objects)</returns>
          public T TextToJSON(string JSONString)
          {
              //check that we aren't passing in empty text
              if (String.IsNullOrEmpty(JSONString))
              {
                  return null;
              }
              else
              {
                  //create a new object
                  T JSONObject = new T();
                  //and create a new serializer for it
                  DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
                  //create a memor stream around the text
                  System.IO.MemoryStream ms = new System.IO.MemoryStream(Encoding.Unicode.GetBytes(JSONString));
                  //do the conversion
                  JSONObject = (T)ser.ReadObject(ms);
                  //tidy up after ourselves
                  ms.Close();
                  //and we're done!
                  return JSONObject;
              }
          }       
      }
      

      这就是它的全部。

      【讨论】:

      • 感谢您的建议。我同意你的观点,使用 DataContractJsonSerializer 更容易,但它也有更多限制。例如日期和时间字段的格式。 Json.Net 支持它可以成功解析的更广泛的格式。这很重要,因为该服务将为第 3 方发布。
      【解决方案3】:

      我从不使用类生成器。当课程很少时,我会手动对其进行编码。当反序列化过程需要很多类时,我更喜欢使用dynamic对象,将其用作here,这样代码可读性更强。

      这是dynamic json的示例用法

      string json = @"{Users:[{Name:'name1',Id:1},{Name:'name2',Id:2}]}";
      dynamic obj = JsonUtils.JsonObject.GetDynamicJsonObject(json);
      foreach (var user in obj.Users)
      {
          Console.WriteLine("{0} {1}", user.Name, user.Id);
      }
      

      【讨论】:

      • L.B,但这种方法缺乏编译时验证。还是我错过了什么?
      猜你喜欢
      • 2013-10-11
      • 1970-01-01
      • 2015-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多