2017-08-07 2 views
1

編集:私は、私は、標準のシリアル化(つまりなしカスタムコンバータ)用を使用したいが、直接のサブタイプをデシリアライズする際(スーパークラスに[JsonConverter(typeof(TConverter))]を適用することで)基本型のためJsonConverterを上書きしているJsonConvert.DeserializeObjectを呼び出し、[JsonConverter]を介してベースタイプに適用されたJsonConverterを無効にする方法はありますか?

:質問を明確に私の派生オブジェクトをデシリアライズします。あたかもJsonConverterをオーバーライドしなかったかのように、deserializeメソッドで使用するSTANDARDシリアル化を指定するにはどうすればよいですか?

私は弾性検索を使用しており、JsonConverterのカスタム実装でJsonConvert.DeserializeObjectを呼び出すことはできません。また、Elasticの属性を使用してコンバータを使用する必要があります。

しかし、このコンバーターを属性として使用すると、すべてのサブクラスにも影響すると思われますが、私は標準コンバータを使用したいので、多くの実装のそれぞれでJsonConverterを実装する必要はありません。

[Route("test")] 
    [HttpPost] 
    public HttpResponseMessage Test([FromBody] JToken json) 
    { 
     var res = json.ToObject<Product>(); // I want an object of ProductImpl type here 
     return Request.CreateResponse(res); 
    } 

    [JsonConverter(typeof(JsonProductConverted))] 
    public abstract class Product 
    { 
    } 

    public class ProductImpl : Product 
    { 
    } 

    public class JsonProductConverted : JsonConverter 
    { 
     public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
     { 
      throw new NotImplementedException(); 
     } 

     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
     { 
      JObject json = JObject.Load(reader); 
      //var type = GetTypeFromId((int) json["typeId"]); // Construct type from field in 
      var type = typeof(ProductImpl); 
      // var res = JsonConvert.DeserializeObject(json.ToString(), type, DEFAULT_JSONCONVERTER_HERE); 
      var res = DeserializeToObjectWithStandardJsonConverter(json, type); 
      return res; 
     } 

     public override bool CanConvert(Type objectType) 
     { 
      return false; 
     } 
    } 

私はデフォルトJsonConverterを指定しない場合、または類似したそれだけで無限ループを作成しJsonProductConvertedコンバータを使用します:

は、これは私がそれを見たいと私のクラス/ロジックです。

+0

質問を明確にするようにしてください。あなたが求めているものを得るのは難しいです。 – Mafii

答えて

1

はあなたProduct型に直接[JsonConverter(typeof(JsonProductConverted))]を追加しているので、あなたはCanReadCanWriteから復帰ProductImplfalseにダミーコンバータを追加することができます。

[JsonConverter(typeof(NoConverter))] 
public class ProductImpl : Product 
{ 
} 

public class NoConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return false; 
    } 

    public override bool CanRead { get { return false; } } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 

    public override bool CanWrite { get { return false; } } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

サンプル.Net fiddleを。

もう1つのオプションはserializer.Populate()です。これにより、オブジェクト自体のコンバーターへの呼び出しを回避できます。

public class JsonProductConverted : JsonTypeInferringConverterBase 
{ 
    protected override Type InferType(Type objectType, JObject json) 
    { 
     //var type = GetTypeFromId((int) json["typeId"]); // Construct type from field in 
     return typeof(ProductImpl); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return false; 
    } 
} 

public abstract class JsonTypeInferringConverterBase : JsonConverter 
{ 
    public override bool CanWrite { get { return false; } } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 

    protected abstract Type InferType(Type objectType, JObject json); 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     var json = JObject.Load(reader); 

     var actualType = InferType(objectType, json); 

     // Construct object (or reuse existingValue if compatible) 
     if (existingValue == null || !actualType.IsAssignableFrom(existingValue.GetType())) 
     { 
      var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(actualType); 
      existingValue = contract.DefaultCreator(); 
     } 

     // Populate object. 
     using (var subReader = json.CreateReader()) 
     { 
      serializer.Populate(subReader, existingValue); 
     } 

     return existingValue; 
    } 
} 

サンプルfiddle #2

+0

これは100%働いた。 Elastic Searchで抽象クラスを保存してから実際のオブジェクトに簡単にデシリアライズすることができます。また、抽象クラスを実装した抽象オブジェクトでも非常に簡単です。 ありがとうございます。 – Nixxon

+0

これはすばらしいですが、私は具体的なクラスにプライベートjsonコンストラクタを追加して、それらを正しくデシリアライズする必要がありました。完全な説明(またはリンク)を得るのはいいと思いますので、契約の側面は私の既存の知識それには及ばないし、決してこの解決法を働かせたことはないだろう – m1nkeh

関連する問題