一种可能的方法是创建一个
自定义ContractResolver
,在序列化特定类型
TTarget
的对象时,添加一个合成的
ExtensionDataGetter
,该Getter返回指定目标的对应
DynamicPropertyManager<TTarget>
中指定属性的
IEnumerable<KeyValuePair<Object, Object>>
。
首先,按以下方式定义契约解析器:
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();
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
;
var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
Console.WriteLine(json);
输出结果符合要求
{"Value":3}
显然,通过将动态属性管理器和目标集合传递给增强的
DynamicPropertyContractResolver<TTarget>
,可以将对象图的序列化扩展到具有动态属性的对象。创建合成的
ExtensionDataGetter
(以及反序列化的
ExtensionDataSetter
)的基本思想是,只要契约解析器具有从正在(反)序列化的目标映射到其
DynamicPropertyManager
的机制,就可以工作。
限制:如果TTarget
类型已经具有扩展数据成员,则此方法将无法正常工作。