2014-10-27 4 views
-2

Это код, при котором переполнение стека происходит только примерно в половине случаев, и я понятия не имею, почему он это делает. Из того, что я видел, это происходит только с Coms (TopCom и т. Д.) В количестве чисел, примерно в 5+, тогда он переполняет стек.Почему мой код C# вызывает переполнение стека

public bool getConnected(int d) { 
    if (topCom.connection != null) { 
     if (d != topCom.connection.id) { 
      if (topCom.connection.id == 0) { 
       return true; 
      } else if (topCom.connection.connected == true) { 
       if (Development.instance.currentDos.buttons[topCom.connection.id].getConnected(id)) { 
        return true; 
       } 
      } 
     } 
    } 

    if (leftCom.connection != null) { 
     if (d != leftCom.connection.id) { 
      if (leftCom.connection.id == 0) { 
       return true; 
      } else if (leftCom.connection.connected == true) { 
       if (Development.instance.currentDos.buttons[leftCom.connection.id].getConnected(id)) { 
        return true; 
       } 
      } 
     } 
    } 

    if (rightCom.connection != null) { 
     if (d != rightCom.connection.id) { 
      if (rightCom.connection.id == 0) { 
       return true; 
      } else if (rightCom.connection.connected == true) { 
       if (Development.instance.currentDos.buttons[rightCom.connection.id].getConnected(id)) { 
        return true; 
       } 
      } 
     } 
    } 

    if (botCom.connection != null) { 
     if (d != botCom.connection.id) { 
      if (botCom.connection.id == 0) { 
       return true; 
      } else if (botCom.connection.connected == true) { 
       if (Development.instance.currentDos.buttons[botCom.connection.id].getConnected(id)) { 
        return true; 
       } 
      } 
     } 
    } 

    return false; 
} 
+0

вы пытались отладить код.? Мы даже не знаем определения вашей структуры - все, что мы знаем, - это то, что код может закончиться бесконечным циклом (когда текущий instan ce и одна из форм 'topCom' * цикл *) - я не могу дать разумное решение, отличное от того, что вы пропустили« HashSet »с * уже посещенными узлами, так что вы можете обнаружить циклы. – Carsten

+0

. Я использовал трассировки стека и отладки. за последние четыре часа я просто пытался очистить код для показа. – Dillyo09

+0

Тогда вам нужно переосмыслить свой алгоритм (о котором мы ничего не знаем) - вы ** должны ** найти способ освободиться от циклов на вашем графике - я сказал вам одну возможность (используя HashSet с посещенными узлами) – Carsten

ответ

1

Это происходит в рекурсивных функциях, где у вас нет базового условия для завершения рекурсии. Вы в основном продолжаете вызывать функцию до тех пор, пока не достигнете переполнения стека. Проследите свой код и выясните, почему он называет себя бесконечно.

+0

Но должен просто пройти корыто до тех пор, пока он не станет истинным или ложным, а трассировка не будет восстановлена, или, в конце концов, то, что моя трассировка стека составляет половину времени. – Dillyo09

+0

И если я понимаю, что вы говорите, если выполняет функцию возврата в середине, она продолжает работать через функцию? – Dillyo09

1

Тот факт, что люди здесь не могут действительно сказать, что вы пытаетесь сделать, - это запах кода.

Большая часть этого факта заключается в том, что у вас невероятное количество гнезд в вашем коде. Вложенные условные выражения увеличивают сложность отладки кода, как вы сейчас открываете. Кроме того, вы можете легко объединить некоторые из ваших условных - все ваших условных в любом отделении верхнего уровня может фактически быть объединены в одно заявление, следующим образом:

if ((topCom.connection != null && d != topCom.connection.id && topCom.connection.id == 0) || 
    (topCom.connection.connected == true && 
    Development.instance.currentDos.buttons[topCom.connection.id].getConnected(id))) 
{ 
    return true; 
} 

return false; 

Насколько я могу себе представить, что нет никакого смысла в имеющие отдельные условные ветви, которые выполняют одну и ту же функцию, например если (a) {return true; } else if (b) {return true; }. Просто переместите логику из else, если в исходное, если условие.

Однако я бы рекомендовал инкапсулировать некоторую или всю эту логику в отдельную функцию, учитывая, что вы выполняете одну и ту же логику для каждого из ваших соединений. Вы можете создать функцию следующим образом:

public bool ConnectionIsValid(connectionObject // replace with the actual type) 
{ 
    if (topCom.connection != null && d != topCom.connection.id && topCom.connection.id == 0) 
     || (topCom.connection.connected == true 
     && Development.instance.currentDos.buttons[topCom.connection.id].getConnected(id)) 
     return true; 

    return false; 
} 

Так что вы могли бы просто назвать ConnectionIsValid на каждом из соединений, а не с помощью 80-несколько строк на условных для каждого соединения.

Также представляется сомнительным, что в этом коде существует исключение StackOverflowException. Если у вас нет циркулярной ссылки, относящейся к любому объекту, на который делается ссылка в этом коде (в этом случае есть вероятность, что вы использовали аксессуар сеттера для присвоения значения той же переменной: объект A { { { это .A = значение; }}

, который всегда будет вызывать переполнение стека, то, скорее всего, вы ввели какой-то рекурсии за рамки включенного кода

+0

Да, но тогда это дало бы одно большое исключение NullReferenceException повсюду. Написал pre-edit – Dillyo09

+0

Ничто не должно приводить к исключению NullReferenceException, если только я не допустил ошибку.Одним из важных аспектов оператора и (&&) является то, что он прекращает работу, если он встречает один ложный оператор в какой-либо конкретной области, поэтому оператор A! = Null && A! = 12 никогда не будет вызывать исключение NullReferenceException, поскольку A! = 12 никогда не будет проверяться, если A будет нулевым. – furkle

Смежные вопросы