Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
803 views
in Technique[技术] by (71.8m points)

c# - Inheriting DefaultContractResolver and treating referenced entities differently

I want to serialize only changed properties. I was managed to do it for the root type, but it contains references to other objects to be serialized (that might even be of the same type).

This is my interface and ContractResolver:

public interface ISelectiveJsonSerialize
{
    IList<string> PropertiesToSerialize { get; }
}

public class JsonSelectiveSerializeContractResolver : DefaultContractResolver
{
    private readonly IList<string> _propertiesToSerialize;

    public JsonSelectiveSerializeContractResolver(IList<string> propertiesToSerialize)
    {
        _propertiesToSerialize = propertiesToSerialize;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        return base.CreateProperties(type, memberSerialization).Where(p => _propertiesToSerialize.Contains(p.PropertyName)).ToList();
    }
}

The property PropertiesToSerialize will have a list of property names that received a value.

This is how I serialize:

        string result = "";
        if (val is ISelectiveJsonSerialize)
        {
            // Don't serialize all properties
            var resolver = new JsonSelectiveSerializeContractResolver(((ISelectiveJsonSerialize)val).PropertiesToSerialize);
            var settings = new JsonSerializerSettings { ContractResolver = resolver };
            result = JsonConvert.SerializeObject(val, Formatting.None, settings);
        }
        else
        {
            // Default serialization
            result = JsonConvert.SerializeObject(val);
        }

        return result;

And this is an example of a type I can serialize:

public class Category : BaseType
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            PropertiesToSerialize.Add("Name");
        }
    }

    private Category _category;
    public Category Category
    {
        get { return _category; }
        set
        {
            _category = value;
            PropertiesToSerialize.Add("Category");
        }
    }
}

As you can understand, If I only set a category for my root type which has a name, it won't serialize the name because the root PropertiesToSerialize doesn't contain "Name", If it would of it would serialize the empty name of the root entity.

Help?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can hook into the conditional property serialization functionality of Json.NET to add a test to determine whether a given property has been modified before serializing it:

public class JsonSelectiveSerializeContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);

        var shouldSerialize = property.ShouldSerialize;
        var name = property.PropertyName;
        property.ShouldSerialize = (o) =>
        {
            var selectiveSerialize = o as ISelectiveJsonSerialize;
            if (selectiveSerialize != null)
            {
                if (!selectiveSerialize.PropertiesToSerialize.Contains(name))
                    return false;
            }
            return shouldSerialize == null || shouldSerialize(o);
        };

        return property;
    }
}

Sample fiddle.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...