【问题标题】:IEnumerable not enumerating in foreachIEnumerable 不在 foreach 中枚举
【发布时间】:2011-09-01 18:20:55
【问题描述】:

我的IEnumerable 之一遇到了我以前从未见过的问题。

我有一个收藏:

IEnumerable<IDependency> dependencies;

foreach 循环中使用。

foreach (var dependency in dependencies)

由于某种原因,这个foreach 不会遍历我的IEnumerable,而是直接跳到最后。

如果我将 foreach 更改为遍历列表,但它似乎工作正常:

foreach (var dependency in dependencies.ToList())

我能做什么导致这种行为?我以前没有在IEnumerable 上遇到过这种情况。

更新

这是在我的方法 GenerateDotString 中运行的 foreach 的完整代码:

foreach (var dependency in dependencies)
{
    var dependentResource = dependency.Resource;
    var lineColor = (dependency.Type == DependencyTypeEnum.DependencyType.Hard) ? "blue" : "red";

    output += labelFormat.FormatWith(dependentResource.Name.MakeDotsafeString(), dependentResource.Name, dependentResource.ResourceType);
    output += relationshipFormat.FormatWith(dependentResource.Name.MakeDotsafeString(), currentName, lineColor);

    if (dependentResource.DependentResources != null)
    {
        output += GenerateDotString(dependentResource, dependentResource.DependentResources, searchDirection);
    }
}

return output;

更新 2

这是包含这个 foreach 的方法的签名(如果有帮助的话)。

private static string GenerateDotString(IResource resource, IEnumerable<IDependency> dependencies, SearchEnums.SearchDirection searchDirection)

更新 3

这是GetAllRelatedResourcesByParentGuidWithoutCacheCheck的方法:

private IEnumerable<IDependency> GetAllRelatedResourcesByParentGuidWithoutCacheCheck(Guid parentCiGuid, Func<Guid, IEnumerable<IDependency>> getResources)
{
    if (!_itemsCheckedForRelations.Contains(parentCiGuid)) // Have we already got related resources for this CI?;
    {
        var relatedResources = getResources(parentCiGuid);
        _itemsCheckedForRelations.Add(parentCiGuid);

        if (relatedResources.Count() > 0)
        {
            foreach (var relatedResource in relatedResources)
            {
                relatedResource.Resource.DependentResources = GetAllRelatedResourcesByParentGuidWithoutCacheCheck(relatedResource.Resource.Id, getResources);
                yield return relatedResource;
            }
        }
    }
}

更新 4

我在此处添加链中的方法,以明确我们如何获取依赖项集合。

上面的方法GetAllRelatedResourcesByParentGuidWithoutCacheCheck接受一个委托,在这种情况下是:

private IEnumerable<IDependency> GetAllSupportsResources(Guid resourceId)
{
    var hardDependents = GetSupportsHardByParentGuid(resourceId);
    var softDependents = GetSupportsSoftByParentGuid(resourceId);
    var allresources = hardDependents.Union(softDependents);
    return allresources;
}

正在调用:

private IEnumerable<IDependency> GetSupportsHardByParentGuid(Guid parentCiGuid)
{
    XmlNode ciXmlNode = _reportManagementService.RunReportWithParameters(Res.SupportsHardReportGuid, Res.DependentCiReportCiParamName + "=" + parentCiGuid);
    return GetResourcesFromXmlNode(ciXmlNode, DependencyTypeEnum.DependencyType.Hard);
}

然后返回:

private IEnumerable<IDependency> GetResourcesFromXmlNode(XmlNode ciXmlNode, DependencyTypeEnum.DependencyType dependencyType)
{
    var allResources = GetAllResources();

    foreach (var nodeItem in ciXmlNode.SelectNodes(Res.WebServiceXmlRootNode).Cast<XmlNode>())
    {
        Guid resourceGuid;
        var isValidGuid = Guid.TryParse(nodeItem.SelectSingleNode("ResourceGuid").InnerText, out resourceGuid);

        var copyOfResource = allResources.Where(m => m.Id == resourceGuid).SingleOrDefault();
        if (isValidGuid && copyOfResource != null)
        {
            yield return new Dependency
            {
                Resource = copyOfResource,
                Type = dependencyType
            };
        }
    }
}

这是返回具体类型的地方。

【问题讨论】:

  • 这取决于循环的内容和IEnumerable
  • 依赖包含31个IDependency的
  • 更重要的是,dependencies 的确切类型是什么以及如何访问它?
  • 好吧......也许我的评论措辞不佳。 dependencies 引用的对象必须是具体类型的实例(如List&lt;IDependency&gt;IDependency[]),而不是接口。我们需要知道具体类型是什么。
  • 会不会是当您实际进行枚举时,某些设置(记住,这是延迟评估)不再有效?例如,你传递给它的委托,在你开始枚举时它还能做它的工作吗?

标签: c# .net .net-4.0 ienumerable


【解决方案1】:

因此,问题似乎与 dependencies 集合有关,无限依赖于其自身。

从我的调试看来,迭代IEnumerable 会导致超时,因此foreach 只是跳过其内容的执行,而ToList() 在超时之前尽可能多地返回。

我可能不正确,但据我所知,情况似乎就是这样。

为了说明这一切是如何发生的,我将解释我昨天所做的代码更改。

应用程序做的第一件事是建立一个按资源类型过滤的所有资源的集合。这些是通过 Web 服务调用从我们的 CMDB 引入的。

我当时所做的是为每个选择的资源(在本例中通过自动完成)我会进行 Web 服务调用并根据其 Guid 获取资源的依赖项。 (递归)

我昨天更改了这一点,以便我们不需要在第二次 Web 服务调用中获取完整的资源信息,而是只需在 Web 服务调用中获取 Guid 列表并从我们的资源集合中获取资源。

我忘记的是,对依赖对象的 Web 服务调用没有按类型过滤,因此它返回的结果在原始资源集合中不存在。

我需要进一步观察,但似乎在这一点上,依赖资源的新集合变得依赖于自身,因此导致 IEnumerable&lt;IDependents&gt; 集合稍后超时。

这就是我今天要到的地方,如果我发现其他任何东西,我一定会在这里记录下来。

总结一下:

如果在 IEnumerable 中发生无限递归,它只会超时 尝试在 foreach 中枚举时。

在 IEnumerable 上使用 ToList() 似乎返回与其一样多的数据 可以在超时之前。

【讨论】:

  • IEnumerable 本身不会超时。如果有无限递归,它(很可能)会抛出StackOverflowException。也许allResources 可能会超时,这取决于它是如何实现的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多