JsonPropertyAttribute在派生类中忽略了对私有财产 [英] JsonPropertyAttribute ignored on private property in derived class

查看:287
本文介绍了JsonPropertyAttribute在派生类中忽略了对私有财产的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题,Json.Net序列化派生的对象,其中有私人属性时。某事像

I have a problem with Json.Net when serializing derived objects, which have private properties. Sth like

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

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

当我序列的实例继承键入属性始终设置为基地。我发现的唯一途径是,财产受到保护或公共和重写的子类。

When I serialize instances of Inherited, the Type property is always set to "Base". The only way I've found that work is that the property is protected or public and overriden in subclass.

为什么会以这种方式工作?那是一个错误?

Why does it work this way? Is that a bug?

推荐答案

看起来这是Json.NET的预期行为。从<一个href="https://github.com/JamesNK/Newtonsoft.Json/blob/1497343173a181d678b4c9bbf60250a12f783f1c/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs"相对=nofollow> ReflectionUtils.cs 的:

Looks like this is an intended behavior of Json.NET. From 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;
                        }

这是在哪里产生的类型属性的列表,你可以看到,有code表示有意prefers同名的基类继承的类属性。

This is where the list of properties for a type is generated, and as you can see, there is code that intentionally prefers identically named properties in the base class to the inherited class.

我不知道为什么Json.NET做到这一点,你可能想报告一个问题,问为什么。在此期间,您可以使用<一个href="http://james.newtonking.com/json/help/index.html?topic=html/T_Newtonsoft_Json_Serialization_IContractResolver.htm"相对=nofollow> IContractResolver 以prevent这种行为选择:

I don't know why Json.NET does this, you might want to report an issue and ask why. In the meantime, you can use an IContractResolver to prevent this behavior selectively:

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

我建议这样做,有选择地,因为我不完全理解为什么Json.NET做的事情一样。在code以上仅覆盖缺省行为的派生类的属性与的Json preferDerivedPropertyAttribute 属性应用自定义。

,然后用它喜欢的:

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

这篇关于JsonPropertyAttribute在派生类中忽略了对私有财产的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆