4 Stimmen

Wie serialisiere ich ein "union-ähnliches" Feld in C# mit Json.NET?

Ich versuche, eine JSON-Datei zu generieren, die im Dojo-Javascript-Framework verwendet wird, und möchte ein position-Attribut zurückgeben, das in einem dojo.place()-Aufruf verwendet werden soll. Der position-Parameter kann entweder eine Zahl oder ein String sein.

Die Verwendung des StructLayout scheint nicht zu funktionieren, da der Serialisierer versuchen würde, sowohl die String- als auch die Integer-Typen auszugeben. Ich überlege, einen benutzerdefinierten ContractResolver zu erstellen, der das CreatePrimitiveContract überschreibt, um eine benutzerdefinierte JsonConverter-Klasse zurückzugeben. Allerdings scheint laut API der JsonConverter auf Basis des Typs erstellt zu werden und nicht eines spezifischen Objektwerts.

Wie kann ich diesen Fall in C# mit dem Json.NET-Serialisierer behandeln?

Vermutlich würde die Lösung zwei Eigenschaften mit benutzerdefinierten Settern umfassen, um die andere Eigenschaft auf null zu setzen, wenn eine gesetzt wird, zusammen mit einer Art benutzerdefinierter Json.Net-Klasse, um die Werte der Eigenschaften zu inspizieren und nur die nicht-null-Werte zu serialisieren.

** Hypothetisches Beispiel **

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

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

// Serialisierungsausgabe
DojoPosition pos;
pos.StrPos = "nur";
var output = JsonConvert.SerializeObject(pos);

// Ausgabe ist: { "position": "nur" }

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

// Ausgabe ist: { "position": 3 }

1voto

sanosdole Punkte 2419

Ich hatte gerade ein ähnliches Problem. Für einfache Manipulation eines Vertrags schau dort nach: Überschreiben des Serialisierungsverhaltens in Json.Net

Zur Lösung eines JsonPrimitiveContract überschreiben Sie die Methode CreateContract.

Hier ist ein Beispiel basierend auf unserer Lösung:

   public class JsonDotNetContractResolver : DefaultContractResolver
   {
      protected override JsonContract CreateContract(Type objectType)
      {
         if (typeof(DojoPosition).IsAssignableFrom(objectType))
         {
            return new JsonPrimitiveContract(objectType.GetGenericArguments()[1])
                      {
                         CreatedType = typeof(object), // Ich bin mir nicht sicher, ob das für dich funktioniert oder notwendig ist...
                         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)
         {
            //....
         }
      }      
   }

Wie man den Typ zum Deserialisieren aus dem Reader bestimmt, ist deine Hausaufgabe ;)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X