【问题标题】:How to serialize static or const member variables using JSON.NET?如何使用 JSON.NET 序列化静态或 const 成员变量?
【发布时间】:2014-06-20 22:32:27
【问题描述】:

我无法在任何地方找到答案,但是当我尝试使用静态或 const 成员变量序列化结构或类时,默认情况下它们不会序列化。如果我尝试通过设置MemberSerialization.OptIn 来强制序列化,则会出现错误。

例如

[JsonObject(MemberSerialization.OptIn)]
public class Test
{    
    [JsonProperty]
    public int x = 1;

    [JsonProperty]
    public static int y = 2;
}

如果我尝试用以下方式序列化这个类:

Test t = new Test();
string s = JsonConvert.SerializeObject( t );

我收到错误 Error getting value from 'y' on 'Test'。如果 y 是 const,也会发生同样的情况。

我的理论是 static 和 const 值存储在内存中的某个特殊位置,并且由于某种原因,Json 序列化程序在尝试访问它们时会死掉。不过,这完全是一种预感,我在C# Reference for Static 中看不到任何帮助。我对 C# 比较陌生 - 目前这确实是一个好奇的问题。

【问题讨论】:

  • 一些记忆无关。如果您将序列化视为获取类实例的快照,则静态变量不是 instances 的一部分。
  • 我无法想象为什么任何人都需要序列化 ​​static 甚至更少的 const 作为 JSON 对象的一部分。使用 const 尤其有趣……如何反序列化为常量?
  • 除了反序列化回相同类型(例如,在 javascript 中使用序列化的 C# 对象)之外,还有其他用例可以序列化 AS JSON。因此,如果它是您感兴趣的数据的一部分,并且无论您在何处使用 json,该类本身都不可用,您可能需要对其进行序列化
  • @Stilgar 那你不是很有想象力,我的朋友。 JSON 被发送到我们的服务器。服务器处理 python 和 javascript 中的数据。静态值是一个版本标识符,它告诉服务器这是什么客户端版本,因此它可以不同地对待各种客户端。那应该是静态数据。我使用readonly 并在类定义中初始化变量,使其成为实例数据,但实际上,IMO 版本说明符应该是静态的。 另外问题是 serialize 而不是 deserialize
  • @L.B 是的,当我这样考虑时,这是完全有道理的。我想这是一个愚蠢的问题,因为我也无法使用t.y 访问值 y ......哦,好吧。有时需要问一些愚蠢的问题......

标签: c# .net json.net


【解决方案1】:

如果它愿意,它当然可以序列化静态变量。序列化是通过使用反射 API 检查对象和类型来完成的,这些 API 允许您做“任何事情”——这些值无法序列化没有技术原因。

但是,默认情况下不支持此功能有一个合乎逻辑的理由:它没有多大意义。您正在序列化一个实例,而staticconst 成员在逻辑上不是实例的一部分,而是整个类的一部分。

也就是说,如果static 是一个属性,你仍然可以序列化它:

[JsonProperty]
public static int y { get; set; } // this will be serialized

当然,您可以通过创建自定义JsonConverter 来完全覆盖序列化程序的行为。

【讨论】:

  • 谢谢。起初我很惊讶,与其说默认是不考虑 static 和 const 成员,不如说是我试图强制它们进入运行时错误。很高兴知道静态属性可以序列化。
【解决方案2】:

从 Json.NET 6.0.4 开始,静态和 const 成员变量以及静态属性在标记为 [JsonProperty] 时将被序列化。来自release notes

  • 修复 - 修复序列化静态字段

因此序列化以下类:

[JsonObject(MemberSerialization.OptIn)]
public class Test
{    
    [JsonProperty]
    int x = 1;

    [JsonProperty]
    static int y = 2;

    [JsonProperty]
    const int z = 333;
}

产生{"x":1,"y":2,"z":333}。示例fiddle

【讨论】:

    【解决方案3】:

    试试这个:

    using Newtonsoft.Json;
    using System.Collections.Generic;
    using System.Linq;
    
    public static string SerializeStaticClass(System.Type a_Type)
    {
            var TypeBlob = a_Type.GetFields().ToDictionary(x => x.Name, x => x.GetValue(null));
            return JsonConvert.SerializeObject(TypeBlob);
    }
    

    我这样做是为了将我们所有的静态类常量序列化为一个 JS 文件,然后将该文件捆绑到一个 Angular 应用程序中。您将生成的 js 对象附加到 $rootScope 并且所有角度代码都可以访问常量。

    hat tip here

    【讨论】:

      【解决方案4】:

      如果您需要在每个实例上序列化一个静态成员(或 const),您可以使用私有实例级访问器作为解决方法:

      [JsonObject(MemberSerialization.OptIn)]
      public class Test
      {
          [JsonProperty]
          public int x = 1;
      
          // static member we want serialized with each instance
          public static int y = 2;
      
          // private accessor to allow Json.net to serialize the static member
          [JsonProperty("y")]
          private int y1 { get { return y; } }
      }
      

      如果您还需要反序列化到此类,这种方法将防止 Json.Net 覆盖静态成员,同时仍允许您自己的代码在需要时对其进行修改。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-05-06
        • 1970-01-01
        • 2019-09-02
        • 2019-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多