Table of Contents

Class RecursionDepthGuard

Namespace
Support
Assembly
Support.dll

Provides methods that can help detect infinite recursion in Debug builds.

public static class RecursionDepthGuard
Inheritance
RecursionDepthGuard
Inherited Members

Examples

Here is how the guard can be used in a real example:

[AlgorithmReference(2, 4)]
public static void MergeSort<T>(IRandomAccessList<T> list, MergeSortConfig config) 
    where T : IComparable<T>
{
    var helpList = new T[list.Count];
    
    void Sort(int start, int end)
    {
        RecursionDepthGuard.Inc();
        
        if (end <= start + 1)
        {
            RecursionDepthGuard.Dec();
            return;
        }
        
        int middle = start + (end - start) / 2;

        if (config.SmallArraySortAlgorithm == MergeSortConfig.SortAlgorithm.Insert && end - start < 12)
        {
            InsertionSort(list, start, end, Comparer<T>.Default);
            RecursionDepthGuard.Dec();
            return;
        }

        Sort(start, middle);
        Sort(middle, end);

        // list[middle] > list[middle + 1]
        if (config.SkipMergeWhenSorted && list.LessOrEqualAt(middle - 1, middle))
        {
            return;
        }
        
        if (config.UseFastMerge)
        {
            FastMerge(list, helpList, start, middle, end);
        }
        else
        {
            Merge(list, helpList, start, middle, end);
        }
        RecursionDepthGuard.Dec();
    }
    
    RecursionDepthGuard.Reset();
    Sort(0, list.Count);
}

Note that Dec() is called for each exit point of the method.

Remarks

To use this feature:

  1. Call Reset(int) before the recursion starts, using a limit that makes sense for your tests.
  2. Call Inc() when the recursion depth increases. Usually at the beginning of a recursive method.
  3. Call Dec() when the recursion depth decreases. Usually at the end of each return.

If the recursion limit is exceeded, an InvalidOperationException is thrown. This makes it easier to use the debugger to find the problem, since the code will break at the point where the recursion limit is exceeded.

All recursion guard calls use the same guard, so algorithms should not be run in parallel.

Methods

Dec()

Decreases the recursion depth counter.

[Conditional("DEBUG")]
public static void Dec()

Inc()

Increases the recursion depth counter.

[Conditional("DEBUG")]
public static void Inc()

Reset(int)

Resets the counter to zero and sets the limit to the specified value.

[Conditional("DEBUG")]
public static void Reset(int limit = 100)

Parameters

limit int