2014-06-11 21 views
3

我有一個裝飾有JsonConverter屬性的類來使用我的自定義轉換器。自定義轉換器的目標是使用一些自定義邏輯對CustomProperty進行序列化。我決定使用JObject.FromObject來自動序列化屬性,而不是編寫代碼來序列化所有基本屬性,而是稍後再執行類似o.Remove("CustomProperty")的操作,然後將自定義序列化成員添加到o
但由於課堂用JsonConverter屬性裝飾,JObject.FromObject再次調用我的ClassAJsonConverter,這導致無限遞歸調用。在調用JObject.FromObject的時候,是否有可能專門告訴json使用它的默認轉換器而不是我自定義的轉換器。當使用JsonConverterAttribute裝飾類時使用默認的JsonSerializer

[Newtonsoft.Json.JsonConverter(typeof(ClassAJsonConverter))] 
public class ClassA 
{ 
    public string A {get; set;} 
    public int B {get; set;} 
    . 
    //20 some properties 
    . 
    public CustomProp CustomProperty {get; set;} 
} 

public class ClassAJsonConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(ClassA); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     . 
     var o = JObject.FromObject(value);  //Here infinite recurrence occur 
     . 
    } 
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     . 
     . 
     . 
    } 
} 

注:我碰到Recursively call JsonSerializer in a JsonConverter但無法實現它。此外,我不想僅爲這一用途添加對AutoMapper的依賴關係。既然問題已經一年多了,有沒有人找到更好的方法來做到這一點?

+0

在'CanConvert'代碼也可以幫助'''不多說。 –

+0

@LB'CanConvert'沒有太多 'return objectType == typeof(ClassA);' –

+0

@AnkitSinha完美的[XY問題](http://www.perlmonks.org/?node=XY+Problem)例。 – I4V

回答

9

如果你用[JsonConverter]屬性修飾了你的班級,那麼序列化程序的所有實例都會知道它。因此,如果在轉換器中使用JObject.FromObject,則即使您嘗試將它傳遞給新的序列化器實例,也會進入無限遞歸循環。

周圍有問題的方法有兩種:

  1. 手動處理每個字段的序列化類而不是調用JObject.FromObject,或
  2. 從類中刪除聲明[JsonConverter]屬性,而是傳遞一個轉換器的實例到串行器。這種方法依賴於CanConvert的正確實現(如您的問題所示),以便轉換器僅適用於預期的類。

例如:

string json = JsonConvert.SerializeObject(classA, new ClassAJsonConverter()); 

如果CustomProperty的序列化不依賴於ClassA其他成員,那麼另一種選擇是創建一個特定的自定義轉換爲CustomProp類,而不是ClassA。然後你的轉換器不必做技巧來擔心其他屬性;它只需要擔心CustomProp本身。


另一種可能的解決方案

我發現可能會爲你工作的解決方案,但感覺有點哈克。我們的想法是在JsonConverter內部創建一個新的JsonSerializer實例,然後在該串行器上使用一個特殊的ContractResolver,它會在請求解析當前轉換器時拒絕其知識。這將允許您在轉換器內部使用JObject.FromObject而不進入遞歸循環,即使您已將[JsonConverter]屬性應用於您的類。這種方法的缺點是,您可能已應用於外部串行器的任何其他設置都不會自動傳送到內部串行器,因此如果需要保留這些設置,則需要手動複製這些設置。

下面是解析的代碼:

class JsonConverterExclusionResolver<T> : DefaultContractResolver 
{ 
    protected override JsonConverter ResolveContractConverter(Type objectType) 
    { 
     JsonConverter conv = base.ResolveContractConverter(objectType); 
     if (conv != null && conv.GetType() == typeof(T)) 
     { 
      // if something asks for the converter we're excluding, 
      // we never heard of it 
      return null; 
     } 
     return conv; 
    } 
} 

有了這個解析器的地方,你就需要修改ClassAJsonConverter使用它是這樣的:

public class ClassAJsonConverter : JsonConverter 
{ 
    private IContractResolver exclusionResolver = 
     new JsonConverterExclusionResolver<ClassAJsonConverter>(); 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(ClassA); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     JsonSerializer innerSerializer = new JsonSerializer(); 
     innerSerializer.ContractResolver = exclusionResolver; 
     // (copy other settings from the outer serializer if needed) 

     var o = JObject.FromObject(value, innerSerializer); 

     // ...do your custom stuff here... 

     o.WriteTo(writer); 
    } 

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

所以沒有辦法創建一個串行器,不包括我的自定義轉換器? –

+0

不適用於應用於該類的'[JsonConverter]'屬性。這是全球性的。 –

+0

好的謝謝。我猜想有一種方法可以從串行器中刪除我的轉換器並使用默認的轉換器。 –