Как все уже сказали, вы делаете бесконечную рекурсию. В отличие от всех остальных, я собираюсь объяснить вам, почему бесконечная рекурсия вызывает переполнение стека:
Во-первых, вы должны понимать, что свойства - это просто методы получения и установки (или функции, если говорить более обобщенно), только то, что они имеют специальный синтаксис, направленный на то, чтобы сделать код, который использует их, более читабельным.
Когда какой-либо код пытается установить свойство, за сценой вызывается функция установки, передавая значение в качестве аргумента. Внутренне ваш s.sessionID = attributeArray[0].ToString();
по сути s.set_sessionID(attributeArray[0].ToString());
. Так что ваш сеттер вызывается. Но сеттер также пытается установить свойство. На самом деле, sessionID = value;
- это просто более чистый способ сказать set_sessionID(value);
. Итак, ваш установщик снова вызывает его. Этот вызов попытается выполнить оператор sessionID = value;
, который вызывает установщик, который пытается выполнить оператор, который вызывает установщик, что ... хорошо, я надеюсь, вы поняли идею.
Функция, которая вызывает себя, называется рекурсивной , а саму технику обычно называют рекурсия . Есть несколько хороших применений для рекурсии, но обычно они используют некоторую форму условного ветвления (поэтому, в конце концов, условие не выполняется, и функция перестает вызывать себя и начинает давать результаты). Однако в вашем случае вы идете к бесконечности и дальше: в вашем коде нет ничего, что могло бы остановить рекурсию (главным образом потому, что она не была предназначена для рекурсии в конце концов), поэтому она будет продолжаться бесконечно. Ну, не бесконечно, просто до тех пор, пока не выйдет ваша программа: P
Теперь, в сочной части этого ответа: какого черта это StackOverflow
? (кроме хорошего сайта Q / A). Почему вы не получаете что-то вроде InfiniteRecursionException
? Конечно, среда выполнения не знает, испортили ли вы или просто делаете что-то необычное (на самом деле, среда выполнения надеется , что вы делаете что-то вменяемое), поэтому она доверяет вам и продолжает делать то, что ваш код приказывает это сделать (в этом случае вызовите установщик свойств).
Но чтобы вызов функции работал, среда выполнения должна вставить «указатель» на вызывающий набор состояний и аргументы вызова в стек. Указатель необходим для того, чтобы среда выполнения могла выяснить, куда идти после возврата вызванной функции. И аргументы необходимы, чтобы функция знала, где их искать (в конце концов, она не знает, откуда она будет вызываться). При каждом вызове эти вещи помещаются на вершину стека, поверх всего, что уже было там.
Обычно функция выдает (извлекает и удаляет) аргументы, делает некоторые вещи и возвращает. В этот момент (аргументов больше нет), «указатель возврата» находится на вершине стека, поэтому среда выполнения выдает его и использует для возврата управления вызывающей стороне.
Именно из-за этого механизма суммирования (все помещаемое в очередь идет поверх всего остального, а вещи извлекаются только из верхней части стека), что цепные вызовы могут работать (например: функция A вызывает функцию B, которая вызывает функцию C : когда C вернется, управление вернется к B, а не к A, но как только сам B вернется, управление вернется к A).
Что произойдет, если вы продолжите лить воду на стакан? Обычно он заполнится (если у него нет отверстия или что-то). Но что, если вы продолжите поливать его водой, когда она уже заполнена? Вода вытекает из стекла, потому что она не может поместиться. Мы могли бы сказать, что вода перетекает из стекла.
Теперь давайте снова посмотрим на вашу бесконечную рекурсию: каждый раз, когда вы устанавливаете свойство, вы делаете (неявно) вызов метода установки, поэтому выдвигаются новый «указатель возврата» и аргумент (значение)в стек.Поскольку вызов выполняет новый вызов до того, как он сможет вернуться, он бесконечно помещает указатели возврата в стек до того, как они получат шанс получить ответ.Таким образом, стек заполняется до тех пор, пока не останется свободной памяти.В этот момент стек переполняется.И, поскольку у программы нет абсолютно никакого способа продолжить работу без помещения чего-либо в стек (чего среда выполнения не может сделать, так как для этого больше нет места), единственная оставшаяся возможность - жаловаться на проблему.Эта жалоба во время выполнения - это то, что обычно называют StackOverflowException
.
BTW, вы можете видеть (упрощенный образец) стека вызовов при отладке вашей программы.Запустите его через отладчик Visual Studio (по умолчанию вы можете сделать это, нажав клавишу F5) и дождитесь его сбоя с исключением SO.Затем найдите окно «Call Stack» (я не могу вспомнить, где оно появляется по умолчанию, перемещало его бесчисленное количество раз), и вы увидите, насколько глубоко среда выполнения смогла пройти рекурсию, прежде чем закончится пространство стека.,Ваш сеттер должен показываться там строка за строкой, бесчисленное количество раз.
И, наконец, упоминание о решениях: все, что вам нужно сделать, это избежать рекурсии.Это означает, что вы не можете вызывать свой установщик изнутри вашего установщика (устанавливая то же свойство из установщика).Это также относится к методам получения (которые вызываются при получении).
Типичный способ сделать это - определить поле «backing» для свойства (переменная-член, где значение будет фактически сохранено), изатем из вашего установщика и получателя вы устанавливаете или возвращаете это поле соответственно.Поскольку поле должно иметь другое имя (типичный подход - использовать подчеркивание (_
), за которым следует имя свойства), компилятор будет знать, что вы задаете поле, а не свойство, поэтому выиграл 'не пытайтесь рекурсивно вызвать установщик вашей собственности.Обычно сеттеры полезны для выполнения «проверок работоспособности» (например, вы можете проверить, что переданное значение не равно null
), но существует много ситуаций, когда нет необходимости проверять ни сеттер, ни геттер, инеобходимость определения вспомогательных полей и самих установщиков / получателей становится скучной, раздутой, избыточной и подверженной ошибкам.По этой причине C # поддерживает «автоматически реализуемые» свойства: если вы замените оба средства доступа на get; set;
(а свойство не является абстрактным), компилятор добавит «безымянное» вспомогательное поле и получит/ установка кода для вас.Обратите внимание, что для того, чтобы это работало, вы должны оставить оба средства доступа: если вы хотите определить один из них, вам также нужно будет определить другой.
Если вы уже поняли концепции, посмотрите надругие ответы, чтобы увидеть много примеров того, как их применять;)
Надеюсь, это поможет.