Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 有没有办法确定一个方法是否被同一个对象递归调用?_C#_Recursion_Stack - Fatal编程技术网

C# 有没有办法确定一个方法是否被同一个对象递归调用?

C# 有没有办法确定一个方法是否被同一个对象递归调用?,c#,recursion,stack,C#,Recursion,Stack,我有一个对象结构,具有罕见但可能的循环。循环是正常的。使用递归方法遍历结构时,循环会导致堆栈溢出。与其在涉及的方法中添加另一个参数,不如找出“this”中的当前方法是否已经在堆栈中。这可能吗?我可能会选择像ThreadLocal计数器这样的东西,在呼叫时增加它,在离开时减少它。通过这种方式,您可以分别计算它在每个线程上输入的时间。这也比扫描堆栈快得多。这也可以用于布尔值,仅用于递归检查 private ThreadLocal<int> _recursiveCounter = new

我有一个对象结构,具有罕见但可能的循环。循环是正常的。使用递归方法遍历结构时,循环会导致堆栈溢出。与其在涉及的方法中添加另一个参数,不如找出“this”中的当前方法是否已经在堆栈中。这可能吗?

我可能会选择像ThreadLocal计数器这样的东西,在呼叫时增加它,在离开时减少它。通过这种方式,您可以分别计算它在每个线程上输入的时间。这也比扫描堆栈快得多。这也可以用于布尔值,仅用于递归检查

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结合起来。我有一个非常类似的问题,下面是我如何解决它的。基本上,我传递一个HashSet并尝试将其添加到这个对象中。如果已添加,则尚未处理此问题

// 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>());
    }
}

可能有兴趣。也许你可以使用lock和Monitor.IsEntered来检测这种情况…@Johnny在同一个线程上,锁是无用的。我不是说锁定,而是检测递归…我在实现深度复制算法时遇到了一个非常类似的问题。当您开始遍历该结构时,请传递一个HashSet并将该对象添加到此HashSet中。当您开始进一步深入结构时,尝试将当前对象添加到HashSet中,如果添加失败,这意味着您进入了一个循环。尽管如此简单且性能卓越,留下痕迹绝对是解决问题的方法。如果我理解得很好,那么通过堆栈是不可能的,因为只有方法,但不能从帧中检索对象id。最后,我添加了一个堆栈变量,该变量记录了方法及其参数的指纹,效果非常好。我将把这个标记为一个答案,因为它启发了解决方案,谢谢@Lajos,我想你说的是StackFrame类。无论如何,使用它是不可行的。因为信息可能会通过内联等方式进行优化,而且从一开始就很难使用。顺便说一句,我认为,这个问题类似于谷歌面试的问题:在有限的硬件资源下,你能说出一个任意的单链接链,如果它包含一个循环吗?我认为这个方法的关键是你应该使用ThreadLocal,这样你就可以确定它是同一根线。所以是同一个堆栈