如何序列化“类似联合”的文件使用 Json.NET 的 C# 字段

发布于 2024-12-15 17:48:33 字数 1471 浏览 4 评论 0原文

我正在尝试生成将在 Dojo javascript 框架中使用的 JSON 文件,并希望返回要在 dojo.place() 调用。 position 参数可以是数字或字符串。

使用 StructLayout 似乎无法按原样工作,因为序列化程序会尝试发出 String 和 Integer 类型。我正在考虑创建一个自定义 ContractResolver< /a> 覆盖 CreatePrimitiveContract 以返回自定义 JsonConverter 类。然而,从 API 来看,JsonConverter 似乎是根据类型而不是特定的对象值创建的。

如何使用 Json.NET 序列化程序在 C# 中处理这种情况?

据推测,该解决方案将涉及两个具有自定义设置器的属性,当其中一个属性与某种自定义 Json.Net 类结合设置时,将另一个属性设置为空,以检查属性的值并仅序列化非空属性。

** 假设示例 **

// C# struct (or class)
[StructLayout(LayoutKind.Explicit)]
struct DojoPosition {
   [JsonProperty(PropertyName="position")]
   [FieldOffset(0)]
   public String StrPos;

   [JsonProperty(PropertyName="position")]
   [FieldOffset(0)]
   public Int32 IntPos;
}

// Serialization output
DojoPosition pos;
pos.StrPos = "only";
var output = JsonConvert.SerializeObject(pos);

// Output is: { "position": "only" }

pos.IntPos = 3;
var output = JsonConvert.SerializeObject(pos);

// Output is: { "position": 3 }

I am attempting to generate a JSON file that will be used within the Dojo javascript framework and would like to return a position attribute to be used in a dojo.place() call. The position parameter can be either a number or a string.

Using the StructLayoutwould not seem to work as-is since the serializer would try to emit both the String and Integer types. I'm looking at creating a custom ContractResolver that overrides the CreatePrimitiveContract to return a custom JsonConverter class. However, looking a the API, it appears that the JsonConverter is created based on type, and not a specific object value.

How can I handle this case in C# using the Json.NET serializer?

Presumably the solution would involve two properties with custom setters to null out the other property when one is set in conjunction with some sort of custom Json.Net class to inspect the values of the properties and only serialize the non-null one.

** Hypothetical Example **

// C# struct (or class)
[StructLayout(LayoutKind.Explicit)]
struct DojoPosition {
   [JsonProperty(PropertyName="position")]
   [FieldOffset(0)]
   public String StrPos;

   [JsonProperty(PropertyName="position")]
   [FieldOffset(0)]
   public Int32 IntPos;
}

// Serialization output
DojoPosition pos;
pos.StrPos = "only";
var output = JsonConvert.SerializeObject(pos);

// Output is: { "position": "only" }

pos.IntPos = 3;
var output = JsonConvert.SerializeObject(pos);

// Output is: { "position": 3 }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

春风十里 2024-12-22 17:48:33

我刚刚遇到了类似的问题。
对于合同的简单操作,请查看: 覆盖 Json.Net 中的序列化行为

用于解析 JsonPrimitiveContract 覆盖 CreateContract 方法。

这是一个基于我们解决方案的示例:

   public class JsonDotNetContractResolver : DefaultContractResolver
   {
      protected override JsonContract CreateContract(Type objectType)
      {
         if (typeof(DojoPosition).IsAssignableFrom(objectType))
         {
            return new JsonPrimitiveContract(objectType.GetGenericArguments()[1])
                      {
                         CreatedType = typeof(object), // Not sure this will work for you, or is necessary...
                         IsReference = false,
                         Converter = DojoPositionConverter,
                      };
         }
         return base.CreateContract(objectType);
      }
      private class DojoPositionConverter : JsonConverter
      {
         public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
         {
            var dp = (DojoPosition) value;
            if(string.IsNullOrEmpty(dp.StrPos))
               serializer.Serialize(writer,dp.IntPos);
            else
               serializer.Serialize(writer,dp.StrPos);
         }
         public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
         {
            //...
         }
         public override bool CanConvert(Type objectType)
         {
            //....
         }
      }      
   }

如何确定要从阅读器反序列化的类型是您的作业;)

I just had a similiar problem.
For simple manipulation of a contract look there: Overriding the serialization behaviour in Json.Net

For resolving a JsonPrimitiveContract override the CreateContract method.

Here is an example based on our solution:

   public class JsonDotNetContractResolver : DefaultContractResolver
   {
      protected override JsonContract CreateContract(Type objectType)
      {
         if (typeof(DojoPosition).IsAssignableFrom(objectType))
         {
            return new JsonPrimitiveContract(objectType.GetGenericArguments()[1])
                      {
                         CreatedType = typeof(object), // Not sure this will work for you, or is necessary...
                         IsReference = false,
                         Converter = DojoPositionConverter,
                      };
         }
         return base.CreateContract(objectType);
      }
      private class DojoPositionConverter : JsonConverter
      {
         public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
         {
            var dp = (DojoPosition) value;
            if(string.IsNullOrEmpty(dp.StrPos))
               serializer.Serialize(writer,dp.IntPos);
            else
               serializer.Serialize(writer,dp.StrPos);
         }
         public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
         {
            //...
         }
         public override bool CanConvert(Type objectType)
         {
            //....
         }
      }      
   }

How to determine the type to deserialize from the reader is your homework ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文