2015-01-11 7 views
3

개인 속성을 가진 파생 개체를 serialize 할 때 Json.Net에 문제가 있습니다. 같은 STH 파생 클래스의 개인 속성에서 JsonPropertyAttribute가 무시되었습니다.

public class Base 
{ 
    [JsonProperty] 
    private string Type { get { return "Base"; } } 
} 

public class Inherited : Base 
{ 
    [JsonProperty] 
    private string Type { get { return "Inherited"; } } 
} 

내가 Inherited의 인스턴스를 직렬화

Type 속성은 항상 "기본"으로 설정되어 있습니다. 그 일을 발견 한 유일한 방법은 속성이 보호되거나 공개되어 있으며 하위 클래스에서 재정의되는 것입니다.

왜 이런 방식으로 작동합니까? 그게 버그 야?

+0

는 귀하의 재산에'new' 키워드를 사용 해봤를

그리고는 좋아 사용할 수 있습니까? –

+0

있습니다. 무시 작업 만 –

+1

개인 속성 대신 개인 필드를 사용하십시오. 제대로 직렬화됩니다. –

답변

2

Json.NET의 의도 된 동작처럼 보입니다. ReflectionUtils.cs에서 :

private static void GetChildPrivateProperties(IList<PropertyInfo> initialProperties, Type targetType, BindingFlags bindingAttr) 
    { 
     // fix weirdness with private PropertyInfos only being returned for the current Type 
     // find base type properties and add them to result 

     // also find base properties that have been hidden by subtype properties with the same name 

     while ((targetType = targetType.BaseType()) != null) 
     { 
      foreach (PropertyInfo propertyInfo in targetType.GetProperties(bindingAttr)) 
      { 
       PropertyInfo subTypeProperty = propertyInfo; 

       if (!IsPublic(subTypeProperty)) 
       { 
        // have to test on name rather than reference because instances are different 
        // depending on the type that GetProperties was called on 
        int index = initialProperties.IndexOf(p => p.Name == subTypeProperty.Name); 
        if (index == -1) 
        { 
         initialProperties.Add(subTypeProperty); 
        } 
        else 
        { 
         PropertyInfo childProperty = initialProperties[index]; 
         // don't replace public child with private base 
         if (!IsPublic(childProperty)) 
         { 
          // replace nonpublic properties for a child, but gotten from 
          // the parent with the one from the child 
          // the property gotten from the child will have access to private getter/setter 
          initialProperties[index] = subTypeProperty; 
         } 

유형의 속성 목록이 생성되는 곳이며, 당신이 볼 수 있듯이, 의도적으로 상속 된 클래스에 기본 클래스에서 같은 이름의 속성을 선호 코드가있다.

왜 Json.NET에서이 작업을 수행하는지 알지 못합니다. 문제를보고하고 이유를 묻는 것이 좋습니다. 한편, 당신은 선택적으로이 문제를 방지하기 위해 IContractResolver을 사용할 수 있습니다 : 나는 완전히 Json.NET 그것이 무엇 않는 이유를 이해하지 않기 때문에

[System.AttributeUsage(AttributeTargets.Property)] 
public class JsonPreferDerivedPropertyAttribute : System.Attribute 
{ 
} 

public class PreferDerivedPropertyContractResolver : DefaultContractResolver 
{ 
    static PropertyInfo GetDerivedPropertyRecursive(Type objectType, Type stopType, PropertyInfo property) 
    { 
     var parameters = property.GetIndexParameters().Select(info => info.ParameterType).ToArray(); 
     for (; objectType != null && objectType != stopType; objectType = objectType.BaseType) 
     { 
      var derivedProperty = objectType.GetProperty(
       property.Name, 
       BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, property.PropertyType, 
       parameters, 
       null); 
      if (derivedProperty == null) 
       continue; 
      if (derivedProperty == property) 
       return derivedProperty; // No override. 
      if (derivedProperty.GetCustomAttribute<JsonPreferDerivedPropertyAttribute>() != null) 
       return derivedProperty; 
     } 
     return null; 
    } 

    protected override List<MemberInfo> GetSerializableMembers(Type objectType) 
    { 
     var list = base.GetSerializableMembers(objectType); 

     for (int i = 0; i < list.Count; i++) 
     { 
      var property = list[i] as PropertyInfo; 
      if (property == null) 
       continue; 
      if (property.DeclaringType != objectType) 
      { 
       var derivedProperty = GetDerivedPropertyRecursive(objectType, property.DeclaringType, property); 
       if (derivedProperty == null || derivedProperty == property) 
        continue; 
       if (derivedProperty != property 
        && (property.GetGetMethod(true) == null || derivedProperty.GetGetMethod(true) != null) 
        && (property.GetSetMethod(true) == null || derivedProperty.GetSetMethod(true) != null)) 
       { 
        list[i] = derivedProperty; 
       } 
      } 
     } 

     return list; 
    } 
} 

내가 선택적으로이 작업을 수행하는 것이 좋습니다. 위의 코드는 사용자 지정 JsonPreferDerivedPropertyAttribute 특성이 적용된 파생 클래스 속성의 기본 동작을 재정의합니다.

public class Base 
{ 
    [JsonProperty] 
    private string Type { get { return "Base"; } } 
} 

public class Inherited : Base 
{ 
    [JsonProperty] 
    [JsonPreferDerivedPropertyAttribute] 
    private string Type { get { return "Inherited"; } } 
} 

public class VeryInherited : Inherited 
{ 
    [JsonProperty] 
    public string VeryInheritedProperty { get { return "VeryInherited"; } } 
} 

public static class TestOverride 
{ 
    public static void Test() 
    { 
     var inherited = new Inherited(); 
     var json1 = JsonConvert.SerializeObject(inherited, Formatting.Indented, new JsonSerializerSettings() { ContractResolver = new PreferDerivedPropertyContractResolver() }); 

     var veryInherited = new VeryInherited(); 
     var json2 = JsonConvert.SerializeObject(veryInherited, Formatting.Indented, new JsonSerializerSettings() { ContractResolver = new PreferDerivedPropertyContractResolver() }); 

     Debug.WriteLine(json1); 
     Debug.WriteLine(json2); 
    } 
} 

그리고 출력은 다음과 같습니다 :

{ 
    "Type": "Inherited" 
} 

{ 
    "VeryInheritedProperty": "VeryInherited", 
    "Type": "Inherited" 
} 
+1

감사합니다. 나는 GitHub에 물어보고 다시보고 할 것이다. –

+0

@Tomasz 모든 뉴스? – pajics

+0

오 이런 일을 완전히 잊었습니다. 다음은 [GitHub 문제] (https://github.com/JamesNK/Newtonsoft.Json/issues/462)입니다. 그것은 정확하게 만족하지 않을 수도 있지만 우리는 그걸로 살아야한다고 생각합니다 :) –

관련 문제