2011-11-14 2 views
4

Je tente de générer un fichier JSON qui sera utilisé dans la structure javascript de Dojo et je voudrais retourner un attribut position à utiliser dans un dojo.place() appel. Le paramètre position peut être soit soit un nombre ou une chaîne.Comment sérialiser un champ "union-like" en C# avec Json.NET

L'utilisation du StructLayout ne semble pas fonctionner telle quelle car le sérialiseur tente d'émettre à la fois les types String et Integer. Je cherche à créer un ContractResolver personnalisé qui remplace le CreatePrimitiveContract pour renvoyer une classe JsonConverter personnalisée. Cependant, en regardant une API, il apparaît que le JsonConverter est créé en fonction du type, et non d'une valeur d'objet spécifique.

Comment puis-je gérer ce cas en C# en utilisant le sérialiseur Json.NET? On peut supposer que la solution impliquerait deux propriétés avec des setters personnalisés pour annuler l'autre propriété quand on est en conjonction avec une sorte de classe Json.Net personnalisée pour inspecter les valeurs des propriétés et ne sérialiser que la non-nulle .

** Exemple ** Hypothétique

// 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 } 

Répondre

1

Je viens d'avoir un problème similaire. Pour la manipulation simple d'un contrat, recherchez-y: Overriding the serialization behaviour in Json.Net

Pour résoudre un remplacement JsonPrimitiveContract, utilisez la méthode CreateContract.

Voici un exemple basé sur notre 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) 
     { 
      //.... 
     } 
     }  
    } 

Comment déterminer le type désérialiser du lecteur est vos devoirs;)

+0

Parfait! Il me manquait la connexion via la méthode 'CreateContract'. Cela m'a mis sur la bonne voie. – Lucas

+0

Json.Net est documenté, mais les points d'entrée sont difficiles à trouver ... – sanosdole

Questions connexes