我遇到了我之前没见过的IEnumerable
之一的问题。
我有一个集合:
IEnumerable<IDependency> dependencies;
在foreach
循环中使用。
foreach (var dependency in dependencies)
由于某些原因,此foreach
不会迭代IEnumerable
而只是跳到最后。
如果我将foreach
更改为循环列表但是它似乎工作正常:
foreach (var dependency in dependencies.ToList())
我能做什么导致这种行为?我以前没有用IEnumerable
经历过这个。
更新:
以下是我的方法foreach
中运行的GenerateDotString
的完整代码:
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
};
}
}
}
这是返回具体类型的地方。
答案 0 :(得分:2)
所以看起来问题与dependencies
集合无关,取决于它自己。
从我的调试看来,迭代IEnumerable
导致超时,因此foreach
只是跳过其内容的执行,其中ToList()
在超时之前尽可能多地返回。
关于这一点我可能不正确,但据我所知,情况似乎就是这样。
为了说明这一切是如何产生的,我将解释我昨天所做的代码更改。
应用程序所做的第一件事就是建立一个按资源类型过滤的所有资源的集合。这些是通过Web服务调用从我们的CMDB引入的。
我当时正在做的是针对所选择的每个资源(在这种情况下通过自动完成)我将进行Web服务调用并根据其Guid获取资源的依赖项。 (递归的)
我昨天改变了这一点,以便我们不需要在第二次Web服务调用中获取完整的资源信息,而只需在Web服务调用中获取Guid列表并从资源集合中获取资源。 / p>
我忘了的是,依赖项的Web服务调用没有按类型过滤,因此返回原始资源集合中不存在的结果。
我需要进一步看一下,但似乎在这一点上,依赖资源的新集合变得依赖于自身,从而导致稍后IEnumerable<IDependents>
集合超时。
这就是今天我要去的地方,如果我发现其他任何东西,我一定会在这里注明。
总结一下:
如果在IEnumerable中发生无限递归,它只会超时 当试图在foreach中进行枚举时。
在IEnumerable上使用ToList()似乎返回与它一样多的数据 可以在超时之前完成。