Сериализация json-объекта с его частными свойствами глубоко - PullRequest
0 голосов
/ 14 октября 2019

Я хочу сериализовать определенные приватные поля, принадлежащие классу неизменяемой библиотеки, как я могу это сделать?

Для сериализации приватных полей я знаю, что могу изменить настройки для сериализации всех приватных полей, но я делаюне хочу сериализовать все поля. Только конкретные поля.

Также для сериализации приватных полей я знаю, что атрибуты JsonProperty или DataMember могут быть записаны в приватных полях. Но я не могу этого сделать, потому что я не могу изменять библиотечные классы. Даже если я могу изменить ее, библиотека зависит от внешней библиотеки после изменения класса библиотеки (например, это зависит от 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. Если вы знаете, вы можете добавить приватные поля для свойства FeatureID.

1 Ответ

0 голосов
/ 14 октября 2019

https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm показывает, что вы можете фильтровать по имени свойства.

ShouldSerialize также можно установить с помощью IContractResolver. Условная сериализация свойства с использованием IContractResolver полезна, если вы не хотите размещать метод ShouldSerialize в классе или вы не объявили класс и не можете.

Страница содержит полную реализацию:

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

(...)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...