C# 通过两阶段反序列化对循环引用进行反序列化
我有一个使用referencesC# 通过两阶段反序列化对循环引用进行反序列化,c#,json,serialization,json.net,C#,Json,Serialization,Json.net,我有一个使用referencespreserverencesshandling=preserverencesshandling.All的序列化程序/反序列化程序 问题是,我有循环引用 这是一个非常简单的例子 class Node { public Node(object value) { Value = value; } public object Value { get; set; } public Node Left { get; se
preserverencesshandling=preserverencesshandling.All
的序列化程序/反序列化程序
问题是,我有循环引用
这是一个非常简单的例子
class Node
{
public Node(object value)
{
Value = value;
}
public object Value { get; set; }
public Node Left { get; set; }
public Node Right { get; set; }
}
我的测试场景是:
var obj = new Node("o")
{
Left = new Node("oL"),
Right = new Node("oR")
};
obj.Right.Right = obj; // Circular reference!
反序列化时,我有以下IReferenceResolver
private class InternalReferenceResolver : IReferenceResolver
{
private readonly Deserializer _par;
public InternalReferenceResolver(Deserializer par)
{
_par = par;
}
public object ResolveReference(object context, string reference)
{
object refObject;
if (!_par._processed.TryGetValue(reference, out refObject))
{
refObject = _par.DeserializeObject(reference);
}
return refObject;
}
public string GetReference(object context, object value)
{
throw new NotSupportedException("Only for Serialization");
}
public bool IsReferenced(object context, object value)
{
return false;
}
public void AddReference(object context, string reference, object value)
{
_par._processed.Add(reference, value);
}
}
private class InternalOnlyCtorContractResolver : IContractResolver
{
private readonly IContractResolver _base;
public InternalOnlyCtorContractResolver(IContractResolver _base)
{
this._base = _base;
}
public JsonContract ResolveContract(Type type)
{
var contract = _base.ResolveContract(type);
var objectContract = contract as JsonObjectContract;
if (objectContract != null)
{
var creatorParameters = new HashSet<string>(objectContract.CreatorParameters.Select(p => p.PropertyName));
var irrelevantProperties = objectContract.Properties
.Where(p => !creatorParameters.Contains(p.PropertyName))
.ToArray();
foreach (var irrelevantProperty in irrelevantProperties)
{
objectContract.Properties.Remove(irrelevantProperty);
}
//TODO Can be optimized better
}
return contract;
}
}
如您所见,当JSON.NET通知我一个新的ref->object(通过AddReference()
)时,我将其添加到字典中
当JSON.NET请求一个对象作为特定引用时(通过resolverence()
),我递归并反序列化该引用
问题是,JSON.NET在调用其AddReference()
之前,会对每个对象引用调用resolverence()
我希望反序列化的流程是:
节点
类只有一个参数化构造函数。如中所述:
JamesNK于2015年11月28日发表评论
非默认构造函数和保留引用不能很好地协同工作,因为在创建父类之前,必须对类型的子值进行反序列化,因此引用解析为null
因此,由于值
无论如何都是一个可变属性,因此应该向节点
添加一个无参数构造函数:
class Node
{
public Node() : this(null) { }
public Node(object value)
{
Value = value;
}
// Remainder unchanged.
}
如果使用设置对其进行标记或反序列化,则它可能是非公共的。如果Value
是不可变的,则需要将其设置为私有的,并用
(如果愿意,可以用它代替Json.NET属性。)
注:
- 由于您的问题缺少参数,您的代码可能会遇到其他无法通过添加无参数构造函数解决的问题
- 有关相关问题,请参阅
- 有关相关问题,请参阅
- 另一件事,我能告诉Json.NET只处理构造函数参数而不处理其余的
不符合第715期。由于对象是一组无序的名称/值对,Json.NET需要解析整个对象,以确保它已加载所有构造函数参数。由于它是单通道序列化程序,非构造函数参数将加载到。。。某物在构建对象之前。Json.NET选择一步将它们反序列化为最终的目标成员类型,而不是中间
和最终的成员类型。这可以从中看出JToken
- 您看到的两阶段反序列化之所以出现,是因为您的
节点
类只有一个参数化构造函数。如中所述:
JamesNK于2015年11月28日发表评论
非默认构造函数和保留引用不能很好地协同工作,因为在创建父类之前,必须对类型的子值进行反序列化,因此引用解析为null
因此,由于值
无论如何都是一个可变属性,因此应该向节点
添加一个无参数构造函数:
class Node
{
public Node() : this(null) { }
public Node(object value)
{
Value = value;
}
// Remainder unchanged.
}
如果使用设置对其进行标记或反序列化,则它可能是非公共的。如果Value
是不可变的,则需要将其设置为私有的,并用
(如果愿意,可以用它代替Json.NET属性。)
注:
- 由于您的问题缺少参数,您的代码可能会遇到其他无法通过添加无参数构造函数解决的问题
- 有关相关问题,请参阅
- 有关相关问题,请参阅
- 另一件事,我能告诉Json.NET只处理构造函数参数而不处理其余的
不符合第715期。由于对象是一组无序的名称/值对,Json.NET需要解析整个对象,以确保它已加载所有构造函数参数。由于它是单通道序列化程序,非构造函数参数将加载到。。。某物在构建对象之前。Json.NET选择一步将它们反序列化为最终的目标成员类型,而不是中间
和最终的成员类型。这可以从中看出JToken
IContractResolver
,它排除了与构造函数无关的所有属性
在第二步中,我使用Populate并使用默认的IContractResolver
private class InternalReferenceResolver : IReferenceResolver
{
private readonly Deserializer _par;
public InternalReferenceResolver(Deserializer par)
{
_par = par;
}
public object ResolveReference(object context, string reference)
{
object refObject;
if (!_par._processed.TryGetValue(reference, out refObject))
{
refObject = _par.DeserializeObject(reference);
}
return refObject;
}
public string GetReference(object context, object value)
{
throw new NotSupportedException("Only for Serialization");
}
public bool IsReferenced(object context, object value)
{
return false;
}
public void AddReference(object context, string reference, object value)
{
_par._processed.Add(reference, value);
}
}
private class InternalOnlyCtorContractResolver : IContractResolver
{
private readonly IContractResolver _base;
public InternalOnlyCtorContractResolver(IContractResolver _base)
{
this._base = _base;
}
public JsonContract ResolveContract(Type type)
{
var contract = _base.ResolveContract(type);
var objectContract = contract as JsonObjectContract;
if (objectContract != null)
{
var creatorParameters = new HashSet<string>(objectContract.CreatorParameters.Select(p => p.PropertyName));
var irrelevantProperties = objectContract.Properties
.Where(p => !creatorParameters.Contains(p.PropertyName))
.ToArray();
foreach (var irrelevantProperty in irrelevantProperties)
{
objectContract.Properties.Remove(irrelevantProperty);
}
//TODO Can be optimized better
}
return contract;
}
}
私有类InternalOnlyTorContractResolver:IContractResolver
{
专用只读IContractResolver_base;
public internalonlytorContractResolver(IContractResolver\u base)
{
这个。_base=_base;
}
公共JsonContract ResolveContract(类型)
{
var合同=_base.ResolveContract(类型);
var objectContract=作为JsonObjectContract的合同;
if(objectContract!=null)
{
var creatorParameters=newhashset(objectContract.creatorParameters.Select(p=>p.PropertyName));
var irrelationproperties=objectContract.Properties
.Where(p=>!creatorParameters.Contains(p。