C# .NET:反序列化 json 树
C# .NET: Deserialize json tree
晚上好,
对于我的具体问题,我必须创建一个菜单(更准确地说是一棵菜单树)。因此,我决定使用具有以下结构的复合设计模式:
- IMenuComponent(定义一些属性等的接口)
- 菜单(包含 IMenuComponent 列表)
- MenuEntry(一片叶子)
所以,我必须在知道返回路径的情况下浏览它。显而易见的答案是 '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"
}
]
}
这与反序列化本身无关,因为它在正常工作。
我的问题是,在将文件反序列化为 'Menu'(根目录)后,我必须访问父目录。
我可以想到两种方法:
- 在运行时使用其 Guid 查找 'parent' - 根据树的大小,性能可能很差;
- 向'Menu'和'MenuEntry'添加一个'Menu' 属性 类以存储'parent'并填充它,方法是找到从 json 反序列化后对应的 Guid。基本上,我会在应用程序启动后立即将它们放在一起,以防止在运行时查找。性能方面也可能很差。
怎么走?我应该怎么做?
作为旁注,我正在使用 Newtonsoft.Json
感谢您的帮助!
@Ian Mercer 的评论实际上帮助我找到了一个简单的解决方案(使用上面 post 中描述的第二种方法)。
第二种方法并不真正依赖Guids。反序列化后,我可以遍历每个菜单集合(反正我可能会这样做)并直接提供对 'parent' 的引用。
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 网络中提到了 PreserveReferencesHandling 属性。最初的问题是 json 不支持循环引用,但这解决了它——这与使用 Guids 的逻辑相同。有多种解决方案,知道总是好的。
谢谢!
晚上好,
对于我的具体问题,我必须创建一个菜单(更准确地说是一棵菜单树)。因此,我决定使用具有以下结构的复合设计模式:
- IMenuComponent(定义一些属性等的接口)
- 菜单(包含 IMenuComponent 列表)
- MenuEntry(一片叶子)
所以,我必须在知道返回路径的情况下浏览它。显而易见的答案是 '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"
}
]
}
这与反序列化本身无关,因为它在正常工作。
我的问题是,在将文件反序列化为 'Menu'(根目录)后,我必须访问父目录。 我可以想到两种方法:
- 在运行时使用其 Guid 查找 'parent' - 根据树的大小,性能可能很差;
- 向'Menu'和'MenuEntry'添加一个'Menu' 属性 类以存储'parent'并填充它,方法是找到从 json 反序列化后对应的 Guid。基本上,我会在应用程序启动后立即将它们放在一起,以防止在运行时查找。性能方面也可能很差。
怎么走?我应该怎么做?
作为旁注,我正在使用 Newtonsoft.Json
感谢您的帮助!
@Ian Mercer 的评论实际上帮助我找到了一个简单的解决方案(使用上面 post 中描述的第二种方法)。
第二种方法并不真正依赖Guids。反序列化后,我可以遍历每个菜单集合(反正我可能会这样做)并直接提供对 'parent' 的引用。
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 网络中提到了 PreserveReferencesHandling 属性。最初的问题是 json 不支持循环引用,但这解决了它——这与使用 Guids 的逻辑相同。有多种解决方案,知道总是好的。
谢谢!