Reputation: 54011
I have a recursive method that builds a tree-like structure of a resource and its related resources.
For each resource that I work with I add it to a class member list which I check on each iteration to make sure that we don't loop infinately on resources that are inter dependent.
Each time I call this recursive method for the first time, I need the class member list to be clear.
At the moment I have a seperate method to do this which I can call between calls to the recursive method.
I'd like to get rid of this method call and reset the list automatically each time.
At the moment I can see two options to solve this problem:
How would you go about solving this problem? What approach would you take?
Here's how my code currently looks:
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();
}
}
Upvotes: 2
Views: 2779
Reputation: 117174
You could try using a recursive lambda expression:
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>();
};
}
}
With this approach multiple concurrent calls can be made without any special logic to clear the list.
Upvotes: 0
Reputation: 70379
It seems to me that the List
shouldn't be a class member but a parameter for the method you call... any direct call happens with null
for this parameter (could even be a default!)... the method allocates the List
in that case and on the recursive calls it just passes the allocated List
...
Upvotes: 1
Reputation: 15130
Just make a method calling an inner method like this:
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
}
}
Upvotes: 1
Reputation: 1503290
I would make a public method which performs the creation, but make the recursive method not care, and take it as a parameter.
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);
}
Upvotes: 4