How to avoid infinite recursion with a custom enumerator?

I made an extension method to find the number of consecutive values ​​in the collection. Since it is generic, I allow the caller to define an "increment", which is Func <>, which must increment the value to check for the presence of the "next" value.

However, if the caller passes the wrong increment (i.e. x => x), it will cause an infinite recursive loop. Any suggestions on clean ways to prevent this?

public static int CountConsecutive<T>(this IEnumerable<T> values, T startValue, Func<T, T> incrementor) { if (values == null) { throw new ArgumentNullException("values"); } if (incrementor == null) { throw new ArgumentNullException("incrementor"); } var nextValue = incrementor(startValue); return values.Contains(nextValue) ? values.CountConsecutive(nextValue, incrementor) + 1 : 1; } 
+6
source share
3 answers

In the purest sense, this is an attempt. The problem with stopping is unsolvable. For all but the simplest cases, you will have to trust those who call your method.

As others have shown, you can do a simple equality check to show that the next value is different. Keeping every visited T will work, but in the end you will have to worry about memory.

As an aside, a StackOverflowException is easily implemented here, so you need to be careful about any dataset that will have many consecutive values.

 var x = Enumerable.Range(1, 100000).CountConsecutive(1, x => x+1); 
0
source

To handle the simplest case, you can do this:

 var nextValue = incrementor(startValue); if (nextValue.Equals(startValue)) { throw new ArgumentException("incrementor"); } 

In general, do the following:

 public static int CountConsecutive<T>(this IEnumerable<T> values, T startValue, Func<T, T> incrementor) { if (values == null) { throw new ArgumentNullException("values"); } if (incrementor == null) { throw new ArgumentNullException("incrementor"); } ISet<T> seen = new HashSet<T>(); return CountConsecutive(values, startValue, incrementor, seen); } private static int CountConsecutive<T>(IEnumerable<T> values, T startValue, Func<T, T> incrementor, ISet<T> seen) { if (!seen.Add(startValue)) { throw new ArgumentException("incrementor"); } var nextValue = incrementor(startValue); return values.Contains(nextValue) ? values.CountConsecutive(nextValue, incrementor) + 1 : 1; } 
+4
source

You can compare nextValue with startValue (you will need T to implement IComparable).

This will solve this error, it will not solve the unpleasant increment error, which returns a cycle - a1, a2, a3, ..., an, a1. I don’t think you want to handle this thing, though

+1
source

Source: https://habr.com/ru/post/902868/


All Articles