IEnumerable не перечисляет в foreach - PullRequest
2 голосов
/ 01 сентября 2011

У меня возникла проблема с одним из моих 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
            };
        }
    }
}

, где возвращается конкретный тип.

1 Ответ

2 голосов
/ 02 сентября 2011

Похоже, проблема заключалась в бесконечной зависимости коллекции dependencies от самой себя.

Из моей отладки кажется, что итерация IEnumerable вызывает тайм-аут, и поэтому foreach простопропускает выполнение его содержимого, когда ToList() возвращает столько, сколько может, до истечения времени ожидания.

Возможно, я не прав в этом, но, насколько я могу судить, дело обстоит именно так.

Чтобы дать некоторое представление о том, как все это произошло, я объясню изменения кода, которые я сделал вчера.

Первое, что приложение делает, это создает коллекцию всех ресурсов, которыефильтруется по типу ресурса.Они доставляются из нашей CMDB через вызов веб-службы.

Затем я делал для каждого ресурса, который был выбран (в данном случае через автозаполнение), я бы сделал вызов веб-службы и получил быиждивенцы за ресурс на основе его гида.(рекурсивно)

Я изменил это вчера, чтобы нам не нужно было получать полную информацию о ресурсе во втором вызове веб-службы, а просто получить список направляющих в вызове веб-службы и захватить ресурсыиз нашей коллекции ресурсов.

Что я забыл, так это то, что вызов веб-службы для иждивенцев не фильтруется по типу, и поэтому он возвращает результаты, которых не было в исходной коллекции ресурсов.

Мне нужно посмотреть немного дальше, но похоже, что в этот момент новая коллекция зависимых ресурсов становилась зависимой от самой себя и, таким образом, позднее для коллекции IEnumerable<IDependents> происходил тайм-аут.

Именно здесьМне нужно сегодня, если я найду что-нибудь еще, я обязательно это заметю здесь.

Подводя итог этому:

Если в IE происходит бесконечная рекурсия, перечислите это 'Просто произойдет тайм-аут при попытке перечисления в foreach.

Использование ToList () в IEnumerable, похоже, возвращает столько данных, сколько можетдо истечения времени ожидания.

...