qui sono i miei pensieri per quanto riguarda la soluzione del problema:
Il problema:
JSON. L'api di deserializzazione personalizzata di Net non è trasparente, cioè influenza la mia gerarchia di classi.
In realtà non è un problema nel caso in cui tu abbia 10-20 classi nel tuo progetto, ma se hai un progetto enorme con migliaia di classi, non sei particolarmente felice del fatto che devi conformare il tuo design OOP con Json Netti requisiti.
Json.Net è valido per gli oggetti POCO che vengono popolati (inizializzati) dopo la creazione. Ma non è la verità in tutti i casi, a volte i tuoi oggetti vengono inizializzati all'interno del costruttore. E per rendere possibile l'inizializzazione è necessario passare argomenti 'corretti'.Questi argomenti 'corretti' possono essere o all'interno di testo serializzato o possono essere già creati e inizializzati qualche tempo prima. Sfortunatamente Json.Net durante la deserializzazione passa valori predefiniti ad argomenti che non capisce, e nel mio caso causa sempre ArgumentNullException.
La soluzione:
Ecco approccio che permette la creazione oggetto reale personalizzato durante la deserializzazione utilizzando qualsiasi insieme di argomenti sia serializzati o non serializzati, il problema principale è che l'approccio sub-ottimale, richiede 2 fasi di deserializzazione per oggetto che richiede deserializzazione personalizzato, ma funziona e permette di deserializzazione oggetti il modo in cui avete bisogno, quindi ecco qui:
In primo luogo abbiamo rimontare la classe CustomCreationConverter seguente modo:
public class FactoryConverter<T> : Newtonsoft.Json.JsonConverter
{
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException("CustomCreationConverter should only be used while deserializing.");
}
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
T value = CreateAndPopulate(objectType, serializer.Deserialize<Dictionary<String, String>>(reader));
if (value == null)
throw new JsonSerializationException("No object created.");
return value;
}
/// <summary>
/// Creates an object which will then be populated by the serializer.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns></returns>
public abstract T CreateAndPopulate(Type objectType, Dictionary<String, String> jsonFields);
/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
/// <summary>
/// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON.
/// </summary>
/// <value>
/// <c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>.
/// </value>
public override bool CanWrite
{
get
{
return false;
}
}
}
.210
Poi creiamo la classe factory che creerà il nostro Foo:
public class FooFactory : FactoryConverter<Foo>
{
public FooFactory(Bar bar)
{
this.Bar = bar;
}
public Bar Bar { get; private set; }
public override Foo Create(Type objectType, Dictionary<string, string> arguments)
{
return new Foo(Bar, arguments["X"], arguments["Y"]);
}
}
Ecco il codice di esempio:
var bar = new Bar("BarObject");
var fooSrc = new Foo
(
bar,
"A", "B"
);
var str = JsonConvert.SerializeObject(fooSrc);
var foo = JsonConvert.DeserializeObject<Foo>(str, new FooFactory(bar));
Console.WriteLine(str);
In questo caso foo contiene un argomento che avevamo bisogno di passare a un costruttore Foo durante deserializzazione.
Non ho idea del perché gli scrittori di serializzatori considerino questa bassa priorità. Ho sempre considerato di essere in grado di costruire oggetti immutabili senza hack di basso livello, una delle funzionalità veramente basilari che un serializzatore basato su un'interfaccia pubblica dovrebbe avere. – CodesInChaos
@CodeInChaos protobuf-net supporta tutte e 4 le opzioni elencate, * e * almeno un'altra (trasformazioni surrogate) ... basta dire ' –
@CodeInChaos come per il motivo: semplicemente, è davvero piuttosto difficile –