gpt4 book ai didi

c# - 如何序列化运行时将 "properties"添加到 Json

转载 作者:行者123 更新时间:2023-11-30 14:47:01 26 4
gpt4 key购买 nike

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

由于这些属性只能通过 ComponentModel.TypeDescriptor 而不能通过反射访问,因此这些属性在 WPF 环境中运行良好,但在序列化环境中运行不佳。

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

我不认为我可以使用这些序列化器中的任何一个,因为它们都不允许修改对实例属性的检索(例如,不可能使用 ContractResolver)。

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

背景:

运行时属性的想法是基于this blog entry .

序列化要求来自于使用 dotNetify 序列化 View 模型以将它们发送到客户端。

目前,我创建了一个 dotnetify 分支,并通过使用 Newtonsoft.Json 和递归帮助程序进行部分序列化,为序列化做了一个临时解决方法。 (如果有兴趣,可以查看差异:the Fork)。

最佳答案

一种可能性是创建一个 custom ContractResolver 即,在序列化 TTarget 类型的特定对象时, 添加合成 ExtensionDataGetter 返回指定目标的 IEnumerable<KeyValuePair<Object, Object>>在其相应的 DynamicPropertyManager<TTarget> 中指定的属性.

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

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;
}
}

然后按如下方式序列化您的对象:

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 用于反序列化)只要契约(Contract)解析器具有某种机制可以将正在(反)序列化的目标映射到它的 DynamicPropertyManager 就可以工作。 .

限制:如果 TTarget type 已经有一个 extension data成员(member),这行不通。

关于c# - 如何序列化运行时将 "properties"添加到 Json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46888732/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com