如何序列化运行时添加的“属性";致杰森 [英] How to serialize runtime added "properties" to Json

查看:141
本文介绍了如何序列化运行时添加的“属性";致杰森的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实现了在运行时向具有特殊SystemComponent.PropertyDescriptor-s的对象添加属性"的可能性.

I implemented the possibility to add "properties" at runtime to objects with special SystemComponent.PropertyDescriptor-s.

由于这些属性只能通过ComponentModel.TypeDescriptor而不是通过Reflection进行访问,因此这些属性在WPF环境中运行良好,而在序列化中则无法使用.

Due to the fact that these properties are only accessible with the ComponentModel.TypeDescriptor and not via Reflection, the properties work well in WPF environment but not with Serialization.

这是因为我知道所有JSON序列化程序都在类型上使用反射.我分析了Newtonsoft.Json,System.Json,System.Web.Script.JavaScriptSerializer,System.Runtime.Serialization.Json.

This is because of all JSON serializers, that I know, use reflection on the type. I analyzed Newtonsoft.Json, System.Json, System.Web.Script.JavaScriptSerializer, System.Runtime.Serialization.Json.

我认为我不能使用任何这些序列化器,因为这些序列化器均不允许修改实例上属性的检索(例如,不可能使用ContractResolver).

I don't think I can use any of these serializers because none of these allow modifying the retrieval of the properties on an instance (e.g. ContractResolver not possible).

有什么方法可以使JSON序列化与这些序列化器之一一起工作吗?也许是通过特殊的配置,覆盖了Serializer上的某些方法或类似方法? 是否有另一个可满足此要求的串行器?

Is there any way to make the JSON serialization work with one of those serializers? Maybe by special configuration, overriding certain methods on the Serializer or similar? Is there another serializer available that fulfills this requirement?

背景:

运行时属性的思想基于此博客条目.

The idea of the runtime properties is based on this blog entry.

序列化要求来自使用dotNetify进行序列化以将其发送到客户端的dotNetify.

The serialization requirement comes from using dotNetify that serializes the viewmodels to send them to the client.

当前,我通过使用Newtonsoft.Json和一个递归帮助器进行了部分序列化,制作了dotnetify的分支,并为序列化提供了一个临时的解决方法. (如果对它感兴趣,可以看一下diff: Fork ).

Currently, I made a fork of dotnetify and made a temporary workaround for the serialization by partially serializing with Newtonsoft.Json and a recursive helper. (You can look at the diff if interested in it: the Fork).

推荐答案

一种可能性是创建一个

One possibility would be to create a custom ContractResolver that, when serializing a specific object of type TTarget, adds a synthetic ExtensionDataGetter that returns, for the specified target, an IEnumerable<KeyValuePair<Object, Object>> of the properties specified in its corresponding DynamicPropertyManager<TTarget>.

首先,如下定义合同解析器:

First, define the contract resolver as follows:

public class DynamicPropertyContractResolver<TTarget> : DefaultContractResolver
{
    readonly DynamicPropertyManager<TTarget> manager;
    readonly TTarget target;

    public DynamicPropertyContractResolver(DynamicPropertyManager<TTarget> manager, TTarget target)
    {
        if (manager == null)
            throw new ArgumentNullException();
        this.manager = manager;
        this.target = target;
    }

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

        if (objectType == typeof(TTarget))
        {
            if (contract.ExtensionDataGetter != null || contract.ExtensionDataSetter != null)
                throw new JsonSerializationException(string.Format("Type {0} already has extension data.", typeof(TTarget)));
            contract.ExtensionDataGetter = (o) =>
                {
                    if (o == (object)target)
                    {
                        return manager.Properties.Select(p => new KeyValuePair<object, object>(p.Name, p.GetValue(o)));
                    }
                    return null;
                };
            contract.ExtensionDataSetter = (o, key, value) =>
                {
                    if (o == (object)target)
                    {
                        var property = manager.Properties.Where(p => string.Equals(p.Name, key, StringComparison.OrdinalIgnoreCase)).SingleOrDefault();
                        if (property != null)
                        {
                            if (value == null || value.GetType() == property.PropertyType)
                                property.SetValue(o, value);
                            else
                            {
                                var serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = this });
                                property.SetValue(o, JToken.FromObject(value, serializer).ToObject(property.PropertyType, serializer));
                            }
                        }
                    }
                };
            contract.ExtensionDataValueType = typeof(object);
        }

        return contract;
    }
}

然后序列化您的对象,如下所示:

Then serialize your object as follows:

var obj = new object();

//Add prop to instance
int propVal = 0; 
var propManager = new DynamicPropertyManager<object>(obj);
propManager.Properties.Add(
    DynamicPropertyManager<object>.CreateProperty<object, int>(
    "Value", t => propVal, (t, y) => propVal = y, null));

propVal = 3;

var settings = new JsonSerializerSettings
{
    ContractResolver = new DynamicPropertyContractResolver<object>(propManager, obj),
};

//Serialize object here
var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);

Console.WriteLine(json);

需要的输出,

{"Value":3}

显然,可以通过将动态属性管理器和目标的集合传递给增强的DynamicPropertyContractResolver<TTarget>,将其扩展为序列化具有动态属性的对象图.创建合成ExtensionDataGetter(和 ExtensionDataSetter DynamicPropertyManager),它就可以工作.

Obviously this could be extended to serializing a graph of objects with dynamic properties by passing a collection of dynamic property managers and targets to an enhanced DynamicPropertyContractResolver<TTarget>. The basic idea, of creating a synthetic ExtensionDataGetter (and ExtensionDataSetter for deserialization) can work as long as the contract resolver has some mechanism for mapping from a target being (de)serialized to its DynamicPropertyManager.

限制:如果TTarget类型已经具有扩展数据成员,这将不起作用.

Limitation: if the TTarget type already has an extension data member, this will not work.

这篇关于如何序列化运行时添加的“属性";致杰森的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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