我的一个 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
接受一个委托(delegate),在本例中是:
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
};
}
}
}
这是返回具体类型的地方。
最佳答案
所以看起来问题与 dependencies
有关收藏无限依赖于自身。
从我的调试来看,似乎迭代了 IEnumerable
导致超时,所以 foreach
简单地跳过其内容的执行,其中 ToList()
在超时之前尽可能多地返回。
我的说法可能不正确,但据我所知,情况确实如此。
为了让大家了解一下这一切是如何发生的,我将解释一下我昨天所做的代码更改。
应用程序做的第一件事是建立一个按资源类型过滤的所有资源的集合。这些是通过网络服务调用从我们的 CMDB 引入的。
我当时所做的是针对每个选择的资源(在本例中通过自动完成)我将进行网络服务调用并根据其 Guid 获取资源的依赖项。 (递归地)
我昨天更改了这个,这样我们就不需要在第二次 web 服务调用中获取完整的资源信息,而是只需在 web 服务调用中获取 Guid 列表并从我们的资源集合中获取资源。
我忘记的是,对家属的 Web 服务调用没有按类型过滤,因此它返回的结果在原始资源集合中不存在。
我需要看得更远一些,但似乎在这一点上,依赖资源的新集合变得依赖于自身,因此导致 IEnumerable<IDependents>
稍后收集超时。
这就是我今天要做的,如果我发现任何其他东西,我一定会在这里注明。
总结一下:
If infinite recursion occurs in an IEnumerable it'll simply timeout when attempting to enumerate in a foreach.
Using ToList() on the IEnumerable seems to return as much data as it can before timing out.
关于c# - IEnumerable 不在 foreach 中枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7274663/