晚上好
对于我的特定问题,我必须创建一个菜单(更准确地说是一个菜单树)。因此,我决定使用具有以下结构的复合设计模式:
- IMenuComponent(一个定义一些属性等的接口)
- 菜单(包含IMenuComponent的列表)
- MenuEntry (a leaf)
所以,我必须在知道回去的路的同时浏览它。最明显的答案是有一个'parent'属性。
我有以下json树:
{
"Guid": "08967257-9306-4717-a76a-e1a4f0050505",
"Parent": null,
"Title": "Main Menu",
"Message": "A sample message",
"Elements": [
{
"$type": "Menu",
"Guid": "26dfca59-9163-4b11-8033-e8ad13f3f5cc",
"Parent": "08967257-9306-4717-a76a-e1a4f0050505",
"Title": "Option 1",
"Message": "Another sample message",
"Elements": [
{
"$type": "MenuEntry",
"Parent": "26dfca59-9163-4b11-8033-e8ad13f3f5cc",
"Title": "Entry 1",
"Message": "Another sample message"
},
{
"$type": "MenuEntry",
"Parent": "26dfca59-9163-4b11-8033-e8ad13f3f5cc",
"Title": "Entry 2",
"Message": "Another sample message"
},
{
"$type": "MenuEntry",
"Parent": "26dfca59-9163-4b11-8033-e8ad13f3f5cc",
"Title": "Entry 3",
"Message": "Another sample message"
}
]
},
{
"$type": "MenuEntry",
"Parent": "08967257-9306-4717-a76a-e1a4f0050505",
"Title": "Option 2",
"Message": "Another sample message"
}
]
}
这与反序列化本身无关,因为它应该工作。
我的问题是,在将文件反序列化到"菜单"(根)后,我必须访问父母。我能想到两种方法:
- 在运行时使用它的Guid查找'父' -根据树的大小可能会导致性能不佳;
- 添加一个'Menu'属性到'Menu'和'MenuEntry'类来存储'parent'并填充它,在从json反序列化后找到相应的Guid。基本上,我将在应用程序启动时立即将其放在一起,以防止在运行时查找。这也可能是糟糕的性能方面。
怎么走?我该怎么做呢?
作为旁注,我使用Newtonsoft.Json
谢谢你的帮助!
@Ian Mercer的评论实际上帮助我找到了一个简单的解决方案(使用我上面帖子中描述的第二种方法)。
第二种方法并不真正依赖于Guids。在反序列化之后,我可以迭代每个菜单集合(无论如何我都可能会这样做)并直接将引用提供给'父'。
private void ConnectTree(Menu menu)
{
foreach (IMenuComponent component in menu.Elements) {
if (component is Menu) {
(component as Menu).ParentMenu = menu;
ConnectTree (component as Menu);
}
else if (component is MenuEntry) {
(component as MenuEntry).ParentMenu = menu;
}
}
}
只需调用ConnectTree(_deserializedMenu)
@Brian Rogers刚刚提到了json net中的PreserveReferencesHandling属性。最初的问题都是关于json不支持循环引用,但这解决了它-它是相同的逻辑使用Guids。有多种解决方案,知道这些总是好的。
谢谢!