Последняя итерация проверки рекурсивного метода - PullRequest
2 голосов
/ 20 октября 2011

У меня есть рекурсивный метод, который создает древовидную структуру ресурса и связанных с ним ресурсов.

Для каждого ресурса, с которым я работаю, я добавляю его в список членов класса, который проверяю на каждой итерации, чтобы убедиться, что мы не зацикливаемся на ресурсах, которые взаимозависимы.

Каждый раз, когда я вызываю этот рекурсивный метод в первый раз, мне нужно, чтобы список членов класса был чистым.

На данный момент у меня есть отдельный метод для этого, который я могу вызывать между вызовами рекурсивного метода.

Я бы хотел избавиться от этого вызова метода и автоматически сбрасывать список каждый раз.

На данный момент я вижу два варианта решения этой проблемы:

  1. Проверка, является ли вызывающий метод таким же, как текущий выполнить метод и, если нет, сбросить список
  2. Вместо этого избавьтесь от элементов рекурсии и очереди, удалив из очереди и ставить в очередь, как мы идем. В конце вызова метода я могу сбросить список.

Как бы вы решили эту проблему? Какой подход вы бы выбрали?

Вот как выглядит мой код:

public class GetAllRelatedResourcesByParentGuidQuery : IGetAllRelatedResourcesByParentGuidQuery
    {
        private readonly IList<Guid> _itemsCheckedForRelations = new List<Guid>();

        public IEnumerable<IDependency> Invoke(Guid parentCiId, 
                                                  IResoucesByIdQuery getResources)
        {
            if (!_itemsCheckedForRelations.Contains(parentCiId))
            {
                var relatedResources = getResources.Invoke(parentCiId);

                _itemsCheckedForRelations.Add(parentCiId);

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

                        yield return relatedResource;
                    }
                }
            }
        }

        public void ResetCheckedItemsCollection()
        {
            _itemsCheckedForRelations.Clear();
        }
    }

Ответы [ 4 ]

3 голосов
/ 20 октября 2011

Я бы сделал открытый метод, который выполняет создание, но сделал бы метод рекурсивный безразличным и принял бы его в качестве параметра.

public List<string> DoSomething(int input)
{
    List<string> results = new List<string>();
    DoSomethingImpl(input, results);
    return results;
}

private void DoSomethingImpl(int input, List<T> results)
{
    // For example...
    if (input == 0)
    {
        return results;
    }
    results.Add("Foo");
    DoSomethingImpl(input - 1, results);        
}
1 голос
/ 20 октября 2011

Мне кажется, что List должен быть не членом класса, а параметром для метода, который вы вызываете ... любой прямой вызов происходит с null для этого параметра (может даже быть по умолчанию!). .. метод выделяет List в этом случае и при рекурсивных вызовах он просто передает выделенное List ...

1 голос
/ 20 октября 2011

Просто создайте метод, вызывающий внутренний метод, например так:

public class GetAllRelatedResourcesByParentGuidQuery : IGetAllRelatedResourcesByParentGuidQuery 
{ 
        private readonly IList<Guid> _itemsCheckedForRelations = new List<Guid>(); 

        public IEnumerable<IDependency> Invoke(Guid parentCiId,  
                                                  IResoucesByIdQuery getResources) 
        {
            Reset();
            return InternalInvoke(parentCiID, getResources);
        }

        private IEnumerable<IDependency> InternalInvoke(Guid parentCiId,  
                                                  IResoucesByIdQuery getResources) 
        {
             //actual implementation, when going recursive, call this internal method
        }
}
0 голосов
/ 20 октября 2011

Вы можете попробовать использовать рекурсивное лямбда-выражение:

public class GetAllRelatedResourcesByParentGuidQuery :
                    IGetAllRelatedResourcesByParentGuidQuery
{
    public IEnumerable<IDependency> Invoke(
            Guid parentCiId,
            IResoucesByIdQuery getResources)
    {
        var checkedItems = new List<Guid>();
        Func<Guid, IResoucesByIdQuery, IEnumerable<IDependency>> invoke = null;
        invoke = (pcid, gr) =>
        {
            if (!checkedItems.Contains(pcid))
            {
                checkedItems.Add(pcid);
                var drs = gr.Invoke(pcid).ToArray();
                foreach (var relatedResource in drs)
                {
                    relatedResource
                        .Resource
                        .DependentResources =
                            invoke(relatedResource.Resource.Id, gr);
                }
                return drs;
            }
            return Enumerable.Empty<IDependency>();
        };
    }
}

При таком подходе можно выполнить несколько одновременных вызовов без какой-либо специальной логики для очистки списка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...