2014-06-11 2 views
3

사용자 정의 변환기를 사용하기 위해 JsonConverter 특성으로 꾸며진 클래스가 있습니다. 사용자 지정 변환기의 목적은 사용자 지정 논리를 사용하여 CustomProperty을 직렬화하는 것입니다. 모든 원시 속성을 serialize하는 코드를 작성하는 대신 JObject.FromObject을 사용하여 속성을 자동으로 serialize하고 나중에 o.Remove("CustomProperty") 같은 것을 수행 한 다음 사용자 지정 serialize 된 멤버를 o에 추가하기로 결정했습니다.
그러나 클래스는 JsonConverter 속성으로 꾸며 졌으므로 JObject.FromObject은 다시 ClassAJsonConverter을 호출하여 infinte 재귀 호출을합니다. 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에 종속성을 추가하고 싶지 않습니다. 질문이 1 년이 넘은 이래로 누구나 더 좋은 방법을 찾았습니까?

+0

CanConvert''의 코드 '... '이별로 도움이되지 않을 수도 있습니다. –

+0

@LB'CanConvert'는 많지 않습니다 'return objectType == typeof (ClassA); ' –

+0

@AnkitSinha 완벽한 [XY 문제] (http://www.perlmonks.org/?node=XY+Problem) 예. – I4V

답변

9

클래스를 [JsonConverter] 속성으로 장식 한 경우 모든 serializer 인스턴스에서 알 수 있습니다. 따라서 컨버터 내에 JObject.FromObject을 사용하면 새로운 serializer 인스턴스를 전달하려고하더라도 무한 재귀 루프가 발생합니다.

  1. 수동 대신 JObject.FromObject를 호출하는 클래스의 각 필드의 직렬화를 처리하거나
  2. 는 클래스 선언에서 [JsonConverter] 속성을 제거하고 대신를 전달합니다

    이 문제를 해결하려면 두 가지 방법이 있습니다 serializer에 대한 변환기의 인스턴스. 이 방법은 변환기가 의도 한 클래스에만 적용되도록 CanConvert (질문에 표시된대로)의 올바른 구현에 의존합니다. 예를 들어

:

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

당신의 CustomProperty의 직렬화 ClassA의 다른 구성원에 의존하지 않는 경우는, 다음 다른 대안은 대신 ClassACustomProp 클래스를 위해 특별히 맞춤 컨버터를 만드는 것입니다. 그러면 변환기는 다른 속성에 대해 걱정할 필요가 없습니다. 단지 CustomProp 그 자체에 대해 걱정해야합니다.


또 다른 가능한 해결책은 당신을 위해 작동 할 수있는 솔루션을 찾았지만 그것은 조금 해키 느낀다. 새로운 JsonSerializer 인스턴스를 JsonConverter 안에 만들고 해당 serializer에서 특수한 ContractResolver을 사용하여 문제를 해결하라는 메시지가 표시 될 때 현재 변환기에 대한 정보를 거부합니다. 이렇게하면 [JsonConverter] 특성을 클래스에 적용한 경우에도 변환기 내에서 JObject.FromObject을 재귀 루프를 사용하지 않고 사용할 수 있습니다. 이 접근 방식의 단점은 외부 직렬 변환기에 적용한 다른 설정이 자동으로 내부 직렬 변환기에 전달되지 않으므로 유지해야하는 경우 수동으로 해당 설정을 복사해야한다는 것입니다.이처럼 사용하도록 ClassAJsonConverter을 수정해야 할 장소에서이 해결와

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; 
    } 
} 

: 여기

은 해결 코드입니다

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

그래서 내 사용자 지정 변환기를 제외한 serializer를 만들 수있는 방법이 없습니까? –

+0

'[JsonConverter]'속성이 클래스에 적용되지 않았습니다. 그것은 세계적입니다. –

+0

감사합니다. 직렬 변환기에서 변환기를 제거하고 기본 변환기를 사용하는 방법이 있다고 생각했습니다. –

관련 문제