Есть ли способ узнать, вызывается ли метод рекурсивно тем же объектом? - PullRequest
0 голосов
/ 26 января 2019

У меня есть структура объекта с редкими, но возможными циклами. (Циклы нормальные.) При прохождении структуры рекурсивным методом, циклы вызывают переполнение стека. Вместо добавления еще одного аргумента к задействованным методам было бы неплохо выяснить, находится ли текущий метод из 'this' в стеке. Это возможно?

Ответы [ 2 ]

0 голосов
/ 26 января 2019

У меня была очень похожая проблема, и вот как я ее решил. В основном я передаю HashSet<object> и пытаюсь добавить this в этот объект. Если он добавлен, то this еще не обработан.

// Dummy class representing an element in the structure
public class A : Strcuture { }

// Dummy class representing an element in the structure
public class B : Strcuture { }

// Dummy class representing an element in the structure
public class C : Strcuture { }

// Base Dummy class for Base Structure elements
public abstract class Strcuture {

    public List<Strcuture> Elements { get; } = new List<Strcuture>();


    public void AddElement(Strcuture element) {
        Elements.Add(element);
    }

    public void RecursiveMethod(HashSet<object> recursiveChecker) {
        if(recursiveChecker == null){
            recursiveChecker = new HashSet<object>();
        }

        var addedThis = recursiveChecker.Add(this);
        if(addedThis == false) {
            // this object has already been handled
            // throw exception?? return early etc
            throw new System.Exception("Already handled object");

        }
        foreach (var elem in Elements) {
            elem.RecursiveMethod(recursiveChecker);
        }
    }

}
class Program
{
    static void Main(string[] args)
    {
        var a = new A();
        var b = new B();
        var c = new C();
        a.AddElement(b);
        b.AddElement(c);
        c.AddElement(a);
        // now our object structure contains a loop
        // A→B→C→A→B...
        a.RecursiveMethod(new HashSet<object>());
    }
}
0 голосов
/ 26 января 2019

Я бы, наверное, пошел за чем-то вроде счетчика ThreadLocal<T>, увеличил бы его при колле и уменьшил при уходе. Таким образом, вы можете посчитать, сколько раз он вошел в каждый поток отдельно. Это также намного быстрее, чем сканирование стека. Это также может быть использовано с логическим значением, только для проверки рекурсии.

private ThreadLocal<int> _recursiveCounter = new ThreadLocal<int>(() => 0);

public void MyMethod(int count)
{
    _recursiveCounter.Value++;
    try
    {
        if(_recursiveCounter.Value > 2)
            Trace.WriteLine($"Recursive exceeds 2 with {_recursiveCounter.Value}");

        if(count== 0)
            return;

        MyMethod(count-1);
    }
    finally
    {
        _recursiveCounter.Value--;
    }
}

Конечно, вы можете обернуть это в классе и комбинировать его с IDisposable using(...).

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