C# 获取指定父级的所有直接子级
我有一个名为GetMenuItems的方法,它返回继承人的体系结构结果。以下是实施方案:C# 获取指定父级的所有直接子级,c#,linq,C#,Linq,我有一个名为GetMenuItems的方法,它返回继承人的体系结构结果。以下是实施方案: public static ObservableCollection<MenuItem> GetMenuItems() { XDocument xDoc = XDocument.Load(DirectoryPaths.DataDirectory_General + "MenuItems.xml"); return LoadMenuItems(xDoc.Descendants("M
public static ObservableCollection<MenuItem> GetMenuItems()
{
XDocument xDoc = XDocument.Load(DirectoryPaths.DataDirectory_General + "MenuItems.xml");
return LoadMenuItems(xDoc.Descendants("MenuItem"));
}
private static ObservableCollection<MenuItem> LoadMenuItems(IEnumerable<XElement> menuItems)
{
return new ObservableCollection<MenuItem>(
menuItems.Select(
x => new MenuItem()
{
Id = Convert.ToDouble(x.Attribute("Id").Value),
Name = x.Element("Name").Value,
ImageData = x.Elements("ImageData").Any() ? x.Element("ImageData").Value : "",
Angle = x.Elements("Angle").Any() ? Convert.ToDouble(x.Element("Angle").Value) : 0,
ScaleX = x.Elements("ScaleX").Any() ? Convert.ToInt32(x.Element("ScaleX").Value) : 0,
ScaleY = x.Elements("ScaleY").Any() ? Convert.ToInt32(x.Element("ScaleY").Value) : 0,
ShortcutKey = x.Elements("ShortcutKey").Any() ? x.Element("ShortcutKey").Value : "",
Background = x.Elements("Background").Any() ? x.Element("Background").Value : "#FF000000",
MouseOver = x.Elements("MouseOver").Any() ? x.Element("MouseOver").Value : "#FF696969",
menuItem = x.Elements("MenuItem").Any() ? LoadMenuItems(x.Elements("MenuItem")) : null
}
)
);
}
公共静态ObservableCollection GetMenuItems()
{
XDocument xDoc=XDocument.Load(directorypath.DataDirectory_General+“MenuItems.xml”);
返回LoadMenuItems(xDoc.substands(“MenuItem”);
}
私有静态ObservableCollection LoadMenuItems(IEnumerable menuItems)
{
返回新的ObservableCollection(
菜单项。选择(
x=>新菜单项()
{
Id=Convert.ToDouble(x.Attribute(“Id”).Value),
名称=x.Element(“名称”).值,
ImageData=x.Elements(“ImageData”)。任意()?x.Element(“ImageData”)。值:“”,
Angle=x.Element(“Angle”).Any()?转换为双(x.Element(“Angle”).Value):0,
ScaleX=x.Element(“ScaleX”).Any()?转换.ToInt32(x.Element(“ScaleX”).Value):0,
ScaleY=x.Element(“ScaleY”).Any()?转换.ToInt32(x.Element(“ScaleY”).Value):0,
ShortcutKey=x.Elements(“ShortcutKey”).Any()?x.Element(“ShortcutKey”)。值:“”,
Background=x.Elements(“Background”).Any()?x.Element(“Background”)。值:“#FF000000”,
MouseOver=x.Elements(“MouseOver”).Any()?x.Element(“MouseOver”)。值:“#FF696969”,
menuItem=x.Elements(“menuItem”)。Any()?LoadMenuItems(x.Elements(“menuItem”):null
}
)
);
}
现在我想得到一个特定父母的所有直接子女
为了更清楚,让我举一个例子:
假设我想获取MenuItem的所有直接子MenuItem,其Id=1
请注意,我需要使用GetMenuItems()方法,因为我不允许访问这些XML文件。您应该将任务分为两部分:
- 查找具有特定ID的菜单
- 得到它的孩子
menuItem
属性,该属性最好命名为Children
或类似的名称
在做了一个重要的更改之后,我将通过递归处理第一部分。如果没有元素,Children
属性将不为null,只需将其设置为空集合即可:
Children = LoadMenuItems(x.Elements("MenuItem")
这样,您可以非常轻松地检查所有子项,即使没有任何子项,也不需要任何空性检查。通常,将缺少项表示为空集合比表示为空引用更容易
因此,要通过ID递归查找菜单项,我将使用:
// TODO: Change the ID type from double to almost anything else. double is a
// *terrible* type to use for IDs.
public MenuItem FindMenuItemById(MenuItem item, double id)
{
return item.Id == id ? item : item.Children
.Select(x => FindMenuItemById(x, id))
.Where(found => found != null)
.FirstOrDefault();
}
如果没有这样的菜单项,它将返回null
。然后您可以使用:
if (item != null)
{
var children = item.Children;
...
}
另外,使用XElement
上的转换运算符和空合并运算符可以更简单地转换其他属性
// Again, change this! Don't use double!
Id = (double) x.Attribute("Id"),
Name = (string) x.Element("Name"),
ImageData = (string) x.Element("ImageData") ?? "",
Angle = (double?) x.Element("Angle") ?? 0d,
ScaleX = (double?) x.Element("ScaleX") ?? 0d,
ScaleY = (double?) x.Element("ScaleY") ?? 0d,
ShortcutKey = (string) x.Element("ShortcutKey") ?? "",
Background = (string) x.Element("Background") ?? "#FF000000",
MouseOver = (string) x.Element("MouseOver") ?? "#FF696969",
那么
menuItem
是儿童的集合吗?(这是一个非传统的名称,它使用null
而不是一个空集合来表示缺少孩子,这实际上是毫无帮助的…@JonSkeet Yes menuItem是一个孩子的集合,我怎么能有一个空集合?我会在我的答案中添加它。回答得很好。我仍然想问两个问题。1) 为什么我不应该对Id使用双数据类型。我这样问是因为我在XML文件中有层次结构,所以我的Id是1,1.1,1.2,2,3,3.1。。。。。。。。。。2) 如果我只想得到顶级物品,那我该怎么办?谢谢你的帮助。@Vishal:关于这两个部分,想一想——第3项的第10个孩子长什么样?我怀疑是“3.10”,与“3.1”的值相同。基本上,菜单项ID不是小数。我建议你用字符串代替。对于获取顶级项目,这就是GetMenuItems()
所提供的,不是吗?是的,我理解使用double是危险的,我希望使用字符串。GetMenuItems()返回包括子项在内的所有项。我不想要孩子。@Vishal:啊,我错过了后代的使用。这就是问题所在—在找到父节点后,使用元素
—我不知道XML是什么样子,所以我不知道它到底是什么样子。例如,它可能是xDoc.Root.Elements(“MenuItem”)
。谢谢。它现在工作得很好。我将GetMenuItems
方法中的xDoc.degents(“MenuItem”)
更改为xDoc.Element(“MenuItem”).Elements(“MenuItems”)