簡體   English   中英

序列化 json object 及其私有屬性深度

[英]Serializing json object with its private properties deeply

我想序列化屬於不可修改庫 class 的特定私有字段,我該怎么做?

要序列化私有字段,我知道我可以修改設置以序列化所有私有字段,但我不想序列化所有字段。 只是特定的字段。

另外為了序列化私有字段,我知道可以在私有字段上寫入 JsonProperty 或 DataMember 屬性。 但我不能這樣做,因為我不能修改庫類。 即使我可以修改它,該庫在修改庫 class 后依賴於外部庫(例如它依賴於 Newtonsoft.Json.dll 如果使用了 JsonProperty 屬性)。

所以我嘗試創建一個自定義屬性來解決它。

// The class to serialize
public class FeatureRepository
{
    // Serialize all private properties that belongs to this object.
    public IDGenerator FeatureIDs;  

    // Do not serialize any private property that belongs to this object!
    public IDGenerator oldFeatureIDs;  
}


// Unmodifiable library class. Also it must be independent from any external libraries.
// There are some private fields but they do not seem.
public class IDGenerator
{
    public IDGenerator();

    public uint GenerateID();
    public bool IsIDUsed(uint id);
    public void ReleaseID(uint id);
    public void UseID(uint id);
}



// Custom contract resolver
public class MyContractResolver : DefaultContractResolver
{
    // Target properties
    private List<SerializableJson> serializableJsons = new List<SerializableJson>();

    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        JsonObjectContract contract = base.CreateObjectContract(objectType);


        // Detect SerializableJsonAttribute and store the property info
        foreach (JsonProperty property in contract.Properties)
        {
            IList<Attribute> attributes = property.AttributeProvider.GetAttributes(typeof(SerializableJsonAttribute), false);

            foreach (SerializableJsonAttribute temp in attributes)
            {
                if (temp != null)
                {
                    SerializableJson serializableJson = new SerializableJson()
                    {
                        PropertyType = property.PropertyType,
                        PropertyName = property.PropertyName
                    };

                    serializableJsons.Add(serializableJson);
                }
            }
        }

        return contract;
    }

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

        // It can compare just the type, can not compare the property name here.
        SerializableJson serializableJson = serializableJsons.Where(temp => temp.PropertyType == objectType).FirstOrDefault();  

        // If the type is target type, add also private fields.
        if (serializableJson != null)
        {
            IEnumerable<MemberInfo> nonPublicMembers = GetFieldsAndProperties(objectType, BindingFlags.NonPublic)
                .Where(m => m is PropertyInfo p ? !IsIndexedProperty(p) : true);

            foreach (MemberInfo member in nonPublicMembers)
                members.Add(member);
        }

        return members;
    }
}


[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Class, AllowMultiple = false)]
public class SerializableJsonAttribute : Attribute
{

}

public class SerializableJson
{
    public Type PropertyType { get; set; }
    public string PropertyName { get; set; }
}



// Finally use the custom attribute SerializableJson
// Both of them will serialized with theirs private fields. 
public class FeatureRepository
{
    [SerializableJson]
    public IDGenerator FeatureIDs;  // I want to serialize all private properties that belongs to this object.

    public IDGenerator oldFeatureIDs;  // I do not want to serialize any private property that belongs to this object!
}

我該如何解決? 或者有什么不同的方法可以解決這個問題而不是我嘗試過的方法?

塊引用

編輯讓我一步一步解釋問題:首先,FeatureRepository被序列化,SerializableJsonAttribute被搜索所有屬性。 它在 FeatureIDs 屬性上找到屬性,但在 oldFeatureIDs 上。 因此它存儲屬性類型“IDGenerator”和屬性名稱“FeatureIDs”。 其次,它開始序列化 IDGenerator。 在序列化 IDGenerator 時,您無法知道序列化是針對“FeatureIDs”屬性或“oldFeatureIDs”屬性完成的。 如果您知道,您可以為“FeatureIDs”屬性添加私有字段。

https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm顯示您可以按屬性名稱過濾。

也可以使用 IContractResolver 設置 ShouldSerialize。 如果您不想在 class 上放置 ShouldSerialize 方法,或者您沒有聲明 class 並且無法聲明,則使用 IContractResolver 有條件地序列化屬性很有用。

該頁面包含完整的實現:

(...)
if (property.DeclaringType == typeof(Employee) && property.PropertyName == "Manager")
        {
            property.ShouldSerialize = ...

(...)

暫無
暫無

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

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