如何编写更复杂的LINQ查询

时间:2013-05-30 19:27:25

标签: c# linq

假设我有:

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));

2 个答案:

答案 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);

如果有人认为CountAny更直观,我觉得后者有一定的可读性优势。两者都应该完成这项工作,我只是更喜欢前者。

答案 1 :(得分:0)

首先,您需要在VDiskList中将Host声明为publicinternal

然后你可以使用这段代码:

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();