ここでは、問題の解決に関する私の考えです。 Netのカスタム非直列化APIは透過的ではなく、つまりクラス階層に影響します。
実際にはプロジェクトに10-20クラスがある場合は問題ありませんが、何千ものクラスのプロジェクトがあれば、JsonでOOPデザインを遵守する必要があるということは特に喜ばしいことではありません.Net要件。
Json.Netは、作成後にポピュレート(初期化)されるPOCOオブジェクトに適しています。しかし、すべてのケースで真実ではなく、コンストラクタ内でオブジェクトを初期化することがあります。そして、その初期化を行うために、あなたは '正しい'引数を渡す必要があります。これらの「正しい」引数は、シリアライズされたテキストの中に入れることも、以前に作成して初期化することもできます。残念ながら、非直列化中のJson.Netは、デフォルト値を彼が理解していない引数に渡し、私の場合は常にArgumentNullExceptionを引き起こします。
ソリューション:
ここ
あるアプローチシリアル化されたまたは非直列化されたいずれかの引数のいずれかのセットを使用して直列化復元時に実際のカスタムオブジェクトの作成を可能にする、主な問題は、サブ最適なアプローチは、それがの2つの段階を必要とすることですオブジェクトごとの直列化復元は、カスタム直列化復元を必要とするが、それは動作し、デシリアライズは、あなたがそれを必要とする方法をオブジェクトことができますので、ここに行く:
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;
}
}
}
:
まず我々はCustomCreationConverterクラスに以下の方法を再構築します
次は私達が私達のは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"]);
}
}
は、サンプルコードです。この場合、fooので
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);
は、私たちが中にFooのコンストラクタに渡すために必要な引数が含まれていますデシリアライゼーション。
シリアライザの作者がこの低い優先度を考慮する理由は考えられません。私は、パブリックインターフェイスベースのシリアライザが持つべき基本的な機能の1つを低レベルでハックしないで、不変のオブジェクトを構築できると常に考えてきました。 – CodesInChaos
@CodeInChaos protobuf-netはリストされた4つのオプションをすべてサポートしています*と*少なくとも1つの他の(代理変換)...ただsayin ' –
@CodeInChaosなぜ:単純に、それは本当にかわいいです –