簡體   English   中英

C# 從父類序列化受保護的屬性 - 問題

[英]C# Serialize Protected Attributes from parent-class - issue

我已經實現了一個帶有“自定義”ContractResolver 的 JsonSerializer,它覆蓋了綁定標志,因此我實際上可以序列化私有成員和受保護成員。 因為我想序列化特定類中的對象。 讓一切都“公開”不是一種選擇。

所以我實現了幾乎可以正常工作的代碼,用於相同 class 上的屬性。 但是,當涉及到來自父類的受保護屬性時,它會在名為“k__Backingfield”的 JSON 字符串中生成一些奇怪的額外信息。

首先,結果/問題:

json-debug: 
{
"jsonTestPrivate":"child-class",
"jsonTestProtected":"Attr from parent class",
"<jsonTestPrivate>k__BackingField":"child-class" //<<--- I want to get rid of THIS :(
}

這個問題似乎只發生在受父類保護的派生屬性上。

--

編碼:

namespace XYZ
{
    class CustomJsonSerializerSettings : Newtonsoft.Json.Serialization.DefaultContractResolver
    {
        public CustomJsonSerializerSettings ContractResolver = null;

        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                            .Select(p => base.CreateProperty(p, memberSerialization))
                        .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                   .Select(f => base.CreateProperty(f, memberSerialization)))
                        .ToList();
            

            props.ForEach(p => { p.Writable = true; p.Readable = true; });

            return props;
        }
    }
}

我的父類抽象了必須在每個可序列化 Object 中引入的 SerializeJson function 並提供了導致問題的父屬性:

namespace XYZ
{
    public abstract class CommandResponse
    {
        public abstract string SerializeJson();
        protected string jsonTestProtected { get; set; } = "Attr from parent class";
        
        //Helper class to serialize/unserialize objects on higher scope.
        //Just derive from this class for every JSON-response/able object and implement abstract function
    }
}

我的子類實現了實際的 function,包括對我已經測試過的東西的一些評論。

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Converters;

namespace XYZ
{
    class CommandActionInvalid : CommandResponse
    {
        private string jsonTestPrivate { get; set; } = "child-class";

        public override string SerializeJson()
        {
            DefaultContractResolver resolverObj = new CustomJsonSerializerSettings();

            //This attributes dont seem to do anything, even if referenced alot in stackoverflow :(
            /*
            resolverObj.IgnoreSerializableAttribute = true;
            resolverObj.IgnoreSerializableInterface = true;
            resolverObj.IgnoreShouldSerializeMembers = true;
            resolverObj.SerializeCompilerGeneratedMembers = false;
            */

            var settings = new JsonSerializerSettings() { ContractResolver = resolverObj };

            return JsonConvert.SerializeObject(this, settings);
        }
    }
}

k__Backingfield字段是秘密的、編譯器生成的自動實現屬性的支持字段。 如果您想在序列化所有其他字段和屬性時跳過它們,您的自定義合同解析器可以重寫如下:

class CustomJsonContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
    const BindingFlags allInstanceMembersFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy;

    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        IEnumerable<MemberInfo> fields = 
            objectType.GetFields(allInstanceMembersFlags)
                // Skip k__BackingField secret backing fields of auto-implemented properties.
                .Where(fi => !fi.IsDefined(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute)));
        IEnumerable<MemberInfo> props = objectType.GetProperties(allInstanceMembersFlags)
                // Skip indexed properties like List[0].
                .Where(pi => pi.GetIndexParameters().Length == 0);
        return fields.Concat(props).ToList();
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        switch (member)
        {
            case FieldInfo fi:
                // Passing MemberSerialization.Fields causes the JsonProperty to be marked as readable and writable
                return base.CreateProperty(fi, MemberSerialization.Fields);
            case PropertyInfo pi:
                var jsonProperty = base.CreateProperty(pi, memberSerialization);
                // Mark the property as readable and writable if the corresponding get and set methods exist even if not public
                if (pi.GetGetMethod(true) != null)
                    jsonProperty.Readable = true;
                if (pi.GetSetMethod(true) != null)
                    jsonProperty.Writable = true;
                return jsonProperty;
            default:
                return base.CreateProperty(member, memberSerialization);
        }
    }
}

筆記:

演示小提琴在這里

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM