Ошибка переполнения стека в C# устанавливала/получала [копируют]

5
задан Marc Gravell 29 March 2010 в 11:49
поделиться

8 ответов

Получатель в первом примере возвращает само свойство, а не резервное поле.

// The property name is "FeedbackComment"
public string FeedbackComment
{
    // And here you are returning "FeedbackComment" which is
    // creating the stack overflow
    get { return FeedbackComment; }
}

К сожалению, нет способа сократить то, что у вас есть, автоматически реализуемые свойства (например, public String FeedbackComment {get; set;} ) должны иметь пустые блоки получения и установки, чтобы быть синтаксически правильными. Во втором примере нет ничего плохого - да, он немного многословен, но ясен, краток и выполняет свою работу.

21
ответ дан 18 December 2019 в 05:19
поделиться

Вы получаете переполнение стека в первом коде, потому что ваш геттер свойства возвращает само свойство.

Это приведет к тому, что getter будет вызываться снова и снова, пока ваш стек не переполнится.

4
ответ дан 18 December 2019 в 05:19
поделиться

Похоже, вы пытаетесь использовать автореализуемые свойства , представленные в C# 3.0, но немного путаете синтаксис.

Возврат FeedbackComment в аксессоре get свойства FeedbackComment создает самореферентный цикл, который продолжает "получать" свойство, так что переполнение стека здесь неудивительно!

Правильный синтаксис для автореализованного свойства следующий. Однако оно не может выполнять никакой обработки ни в аксессоре get, ни в аксессоре set (по определению).

public class Feedback
{
    public Feedback() { }

    public string FeedbackComment
    {
        get;
        set;
    }

    // other fields 

    // methods
}

В вашем случае, поскольку вы хотите выполнить обработку в аксессоре 'set', вы хотите сделать это стандартным способом, используя опорное поле.

2
ответ дан 18 December 2019 в 05:19
поделиться

Код, вызвавший StackOverflowException, не предоставляет подложное поле для свойства, а аксессор get возвращает само свойство, что и вызывает переполнение стека. Второй пример действительно предоставляет базовое поле и возвращает его содержимое.

2
ответ дан 18 December 2019 в 05:19
поделиться

Помните, что свойства на самом деле являются методами - их компилятор преобразует их в T вызовы get_Property () и set_Property (T value) - нет хранилища (если не используются автоматические свойства, но происходит то, что компилятор автоматически создает резервное поле. Итак, что ваш пример переполнения стека выглядит так:

public class Feedback
{

    public Feedback() { }

    // Getter
    public string get_FeedBackComment() {
        return get_FeedBackComment();
    }
    // Setter
    public void set_FeedBackComment(string value) {
         System.Web.HttpUtility.HtmlEncode(value);
    }
}

Таким образом, вы получили вызов функции, который навсегда вызвал ее сам, поэтому стек переполнился, потому что каждый вызов - это выталкивание стека. А параметр вызывал функцию, но никогда нигде не сохранял ее значение.

{ {1}}
2
ответ дан 18 December 2019 в 05:19
поделиться

Думаю, вам не хватает фундаментального понимания свойств. Свойство не может содержать никаких данных, это просто пара метода получения и метода установки (есть также свойства, у которых есть только методы получения или установки).

Метод получения - это, по сути, метод, который не принимает аргументов и возвращает значение типа свойства, установщик, с другой стороны, - это метод без возвращаемого значения и аргумент типа свойства, называемый значением. C # скрывает оба этих метода и объединяет их в свойство, и вы можете вызывать их как обычное поле.

Ваша первая реализация эквивалентна:

public class Feedback
{
    public string get_FeedbackComment()
    {
        return get_FeedbackComment();
    }

    public void set_FeedbackComment(string value)
    {
        System.Web.HttpUtility.HtmlEncode(value);
    }
}

Теперь вы можете увидеть, где находится рекурсия и в чем заключается ваша ошибка. Вдобавок, когда вы посмотрите на сеттер, вы заметите, что он ничего не устанавливает.Возвращаемое значение HtmlEncode нигде не сохраняется. Вам необходимо предоставить вспомогательное поле (например, во втором фрагменте кода).

Однако в C # 3.0 и выше есть автоматически реализованные свойства, которые вы объявляете следующим образом. Также имейте в виду, что компилятор C # автоматически создаст резервное поле, поэтому в основном оба способа одинаковы, но вы получаете большую гибкость с первым, потому что с автоматически реализованными свойствами вы не можете добавить более сложное поведение, чем просто простая установка и получение значений ( по крайней мере, в том классе, в котором вы его объявляете, делая его виртуальным, открывает возможности для расширения логики свойств в подклассах ..).

public class Feedback
{
    public string FeedbackComment
    {
        get;
        set;
    }
}

С уважением,
Оливер Ханаппи

1
ответ дан 18 December 2019 в 05:19
поделиться

Геттер ссылается на себя (как указывает Эндрю), но сеттер также ошибается.

Этот код:

set { System.Web.HttpUtility.HtmlEncode(value); }

... на самом деле ничего не устанавливает. Метод HtmlEncode возвращает закодированное значение, фактически не изменяет value.

Еще одна вещь, которую вы должны иметь в виду, это то, что если вы HtmlEncode-ing на пути, вам нужно HtmlDecode на выходе, в противном случае вы можете получить несколько кодировок (которые не являются идемпотентными). Если вы пытаетесь «автоматизировать» процессы кодирования, то класс обычно выглядит примерно так:

public class Foo
{
    private string bar;

    public string Bar
    {
        get { return HttpUtility.HtmlDecode(bar); }
        set { bar = HttpUtility.HtmlEncode(value); }
    }

    public string SafeBar
    {
        get { return bar; }
    }
}

Или вы можете изменить безопасную/небезопасную логику,Например:

public string Bar
{
    get { return bar; }
    set { bar = HttpUtility.HtmlEncode(value); }
}

public string UnsafeBar
{
    get { return HttpUtility.HtmlDecode(value); }
}

В любом случае ваш класс должен явно указать тот факт, что он выполняет какое-то кодирование, в противном случае, если вы пишете код следующим образом:

Foo foo1 = new Foo();
foo1.Bar = "<test>";
Foo foo2 = new Foo();
foo2.Bar = foo1.Bar;

... тогда вы начнете видеть кучу уродливых escape-персонажей в выходных данных foo2. Бар. Сделайте контракт вашего класса ясным, он должен либо выполнять оба кодировки и , либо не делать ни того, ни другого.

8
ответ дан 18 December 2019 в 05:19
поделиться

Это отличный пример отработки неправильного использования Рекурсивного программирования;)

Проблема не в свойствах, а в общем получении значения из любого метода, например:


public int GiveMeValue()
{
  return GiveMeValue();
}

public void SetValue(int value)
{
   SetValue(value);
}

В любом случае свойства DotNet - это особый тип методов. не так ли?

1
ответ дан 18 December 2019 в 05:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: