假设我有:
public class Cluster
{
List<Host> HostList = new List<Host>();
}
public class Host
{
List<VDisk> VDiskList = new List<VDisk>();
}
public class VDisk
{
public string Name {get; set}
}
我需要Cluster对象中具有给定名称的VDisk的所有主机。我可以用foreach做,但宁愿有一个LINQ查询。我尝试了一个SelectMany(),但它返回VDisk而不是Hosts。我需要实现自定义Comparer吗?
这是我试过的:
Cluster CurrentCluster = new Cluster();
// add some hosts here
VDisk vdisk = new VDisk();
vdisk.Name="foo";
所以现在我想要所有拥有名为“foo”
的虚拟磁盘的主机这将返回虚拟磁盘,而不是主机:
CurrentCluster.Hosts.SelectMany(h => h.VDisks.Where(v => v.Name == vdisk.Name));
答案 0 :(得分:7)
SelectMany
确实会返回内部集合,扁平化为一个大集合。您希望谓词位于Hosts
上,而不是VDisks
,因为您要查找的是Hosts
列表。
这可能有效:
CurrentCluster.Hosts.Where(h => h.VDisks.Any(v => v.Name == vdisk.Name));
它基本上说,“返回所有主机,其中任何VDisk匹配条件v.Name == vdisk.Name
。
我也看到不了解Any
的开发人员写了这样的东西:
CurrentCluster.Hosts.Where(h => h.VDisks.Count(v => v.Name == vdisk.Name) > 0);
如果有人认为Count
比Any
更直观,我觉得后者有一定的可读性优势。两者都应该完成这项工作,我只是更喜欢前者。
答案 1 :(得分:0)
首先,您需要在VDiskList
中将Host
声明为public
或internal
。
然后你可以使用这段代码:
var hostList = new List<Host>();
var givenVDiskName = "sample name";
var selectedHosts = (from h in hostList
where h.VDiskList.Any(vd => vd.Name == givenVDiskName)
select h).ToList();