J'ai un convertisseur que je ne veux utiliser que lors de la désérialisation. J'ai donc mis CanWrite à false, ce qui fonctionne bien et tout se sérialise correctement. La chaîne Json contient alors un graphe d'objets à l'intérieur duquel il y a une SantaClauseCollection avec un tableau d'éléments SantaClause et un $type indiquant qu'ils sont de type concret SantaClause.
Cependant, lorsqu'il rencontre une collection de SantaClaus pendant la désérialisation, il n'appelle jamais CanConvert (j'ai un point d'arrêt et je vois la collection de SantaClaus, j'appuie sur F5 pour continuer, qui devrait ensuite atteindre le point d'arrêt à nouveau lorsqu'il rencontre un élément dans la collection de SantaClaus, mais ce n'est pas le cas). Il n'essaie pas d'appeler CanConvert lorsqu'il arrive à l'élément SantaClaus. Sans même appeler CanConvert pour cet élément afin de vérifier si mon convertisseur peut le gérer, il essaie de le désérialiser lui-même, ce qui ne fonctionnera pas parce que la classe n'a pas de constructeur par défaut ni de constructeur avec des conventions de correspondance entre les noms de propriétés :
Impossible de trouver un constructeur à utiliser pour le type SantaClaus. Une classe doit avoir un constructeur par défaut, un constructeur avec des ou un constructeur marqué par l'attribut JsonConstructor.
Je comprends pourquoi j'obtiens cette erreur, mais le problème est qu'elle indique que Json.net a essayé de désérialiser l'objet, au lieu d'appeler CanConvert pour vérifier et voir si mon convertisseur voulait gérer la désérialisation à la place.
Pourquoi CanConvert n'est-il pas appelé pour chaque élément de la collection ?
Mon convertisseur :
class SantaClaus2JsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SantaClaus);
}
/// <summary>
/// Deserializes a SantaClaus as a SantaClausEx which has a matching constructor that allows it to deserialize naturally.
/// </summary>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return serializer.Deserialize<SantaClausEx>(reader);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
public override bool CanRead
{
get
{
return true;
}
}
public override bool CanWrite
{
get
{
return false;//We only need this converter when reading.
}
}
}
SantaClausEx hérite simplement de SantaClaus pour ajouter un constructeur avec un paramètre renommé pour correspondre aux propriétés :
class SantaClaus //a third party class I can't modify
{
string Name {get;set;}
public SantaClaus(string santaClauseName) { this.Name = santaClauseName }
}
class SantaClausEx:SantaClaus
{
//provide a constructor with param names matching property names
public SantaClausEx(string name) : base(name)
}
Json.net ne peut pas désérialiser un SantaClaus, mais il peut désérialiser un SantaClauseEx.
J'utilise cette classe SantaClauseEx partout et cela fonctionne très bien, mais je voulais créer un convertisseur pour faire cela automatiquement.
Voici à quoi ressemble le Json pour la collection :
SantaClausCollection: [
{
$type: "SantaClaus, XMasClasses.NET20"
Name: "St. Bob"
},
{
$type: "SantaClaus, XMasClasses.NET20"
Name: "St. Jim"
}
]