【发布时间】:2015-10-18 18:56:47
【问题描述】:
晚上好,
对于我的具体问题,我必须创建一个菜单(更准确地说是菜单树)。因此,我决定使用具有以下结构的复合设计模式:
- IMenuComponent(定义一些属性等的接口)
- 菜单(包含 IMenuComponent 列表)
- MenuEntry(一片叶子)
所以,我必须在知道返回路径的同时浏览它。显而易见的答案是拥有一个“父”属性。
我有以下 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' 和 'MenuEntry' 类中添加一个 'Menu' 属性来存储 'parent' 并在从 json 反序列化后通过查找相应的 Guid 来填充它。基本上,我会在应用程序启动时将它放在一起,防止在运行时查找。这在性能方面也可能很糟糕。
怎么走?我该怎么做?
附带说明,我使用的是Newtonsoft.Json
感谢您的帮助!
【问题讨论】:
-
Guid 在应用中有什么意义吗?还是它只是您的序列化逻辑的一部分?如果是后者,为什么要拥有它?树结构已经是数据中固有的;对其进行第二个表示几乎没有什么好处,并且可能与实际结构发生冲突。
-
即使树结构已经存在于数据中(即使在反序列化之后),知道“父级”的唯一方法是存储一个 id,在这种情况下是一个 Guid。拥有“菜单”类型的“父”将具有循环引用,这首先是不可能序列化的。但是,如我的帖子所述,在反序列化后填充该属性是可能的。
-
实际上,在第二个选项中,我必须遍历整个树并比较 Guid。既然我这样做了,我可以即时存储“菜单”属性,而不需要指导。我会试一试,稍后再发布结果。
-
@Apidcloud - 仅供参考:如果您使用
PreserveReferencesHandling设置,是可以在 Json.Net 中序列化循环引用。但是,这将导致 Json.Net 向 JSON 写入额外的$id和$ref属性,这可能会或可能不会被您接受。当您反序列化具有这些额外元数据的 JSON 时,Json.Net 会自动为您重新连接所有对象引用。 -
我不知道那个!只试了
ReferenceLoopHandling,没用。由于它是应用程序资产,我相信这样做是可以的。谢谢