Как сериализовать "подобное объединению" поле в C # с Json.NET - PullRequest
4 голосов
/ 14 ноября 2011

Я пытаюсь сгенерировать файл JSON, который будет использоваться в среде JavaScript Dojo, и хотел бы вернуть атрибут position, который будет использоваться в вызове dojo.place(). Параметр position может быть или числом или строкой.

Использование StructLayout, по-видимому, не будет работать как есть, так как сериализатор будет пытаться испускать оба типа String и Integer. Я смотрю на создание пользовательского ContractResolver, который переопределяет CreatePrimitiveContract для возврата пользовательского JsonConverter класса. Однако, глядя на API, кажется, что JsonConverter создается на основе типа, а не конкретного значения объекта.

Как мне справиться с этим делом в C # с помощью сериализатора Json.NET?

Предполагается, что решение будет включать два свойства с пользовательскими установщиками для обнуления другого свойства, когда оно устанавливается вместе с каким-то пользовательским классом 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 }

1 Ответ

1 голос
/ 15 ноября 2011

У меня просто была похожая проблема. Для простого манипулирования контрактом посмотрите здесь: Переопределение поведения сериализации в 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)
         {
            //....
         }
      }      
   }

Как определить тип десериализации из читателя - ваша домашняя работа;)

...