Как избежать рекурсии собственности - программирование
Подтвердить что ты не робот

Как избежать рекурсии собственности

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

public int Test 
{
   get { return this.test; }
   set { this.Test = value; }
}
private int test;

Вы случайно положили верхний регистр T в этот сеттер, и вы открыли себя до StackoverflowException. Что еще хуже, если вы не определили его, часто визуальная студия автоматически исправит корпус для вас в недопустимом состоянии.

Я сделал что-то подобное, но в конструкторе в последнее время:

public TestClass(int test)
{
    this.Test = Test;
}

К сожалению, здесь вы не получаете исключение StackOverflowException, теперь у вас есть ошибка программирования. В моем случае это значение было передано в WebService, который вместо этого использовал значение по умолчанию (которое не было 0), что заставило меня пропустить тот факт, что я неправильно назначил его. Все тесты интеграции прошли, потому что эта служба не говорила

"Эй, ты забыл это действительно важное поле!"

Какие шаги я могу предпринять, чтобы избежать такого поведения? Мне всегда советовали не определять такие переменные, как следующие, и мне они не нравятся лично, но я не могу придумать никаких других вариантов:

private int _test;
private int mTest;

ИЗМЕНИТЬ

Причины, что подчеркивание или префикс m нежелательны, как правило, я могу думать:

  • читабельность
  • Чуть сложнее прокручивать элементы, если вы наследуете от сторонних классов, когда вы получаете сочетание стилей.
4b9b3361

Ответ 1

Лучший способ - использовать здесь "Авто реализованные свойства".

public int Test { get; set; }

Если невозможно использовать "Автоматически реализованные свойства" по какой-либо причине, используйте префикс _ (я не предпочитаю, хотя).

Если вы также не предпочитаете использовать некоторые префиксы, у вас есть другой вариант. Вам не нужно писать код свойства вручную. Пусть IDE сделает это за вас; таким образом вы можете избежать неосторожных ошибок. (Я не знаю, как я пропустил это в оригинальном ответе)

Просто введите

private int test;

Выберите поле, щелкните правой кнопкой мыши Refactor- > Encapsulate Field. IDE будет генерировать фрагмент свойств для вас, как показано ниже.

public int Test
{
    get { return test; }
    set { test = value; }
}

Вам не нужно беспокоиться о нажатии контекстного меню. Если вы предпочитаете клавиатуру, ярлык Ctrl + R + E.

Или получите Resharper, он немедленно укажет вашу глупую ошибку.

Ответ 2

Интеграция проверяет все прошедшие

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

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

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

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

  • Напишите тест, чтобы воспроизвести ошибку.
  • Исправить ошибку.
  • Используйте тест для проверки исправления.

Конечно, это касается только одного случая, а не каждого определения свойства в вашем коде. Но если это происходит много, тогда у вас может возникнуть кадровая проблема, а не техническая проблема. Кто-то в команде, ну, неряшливый. Решение этой проблемы может быть не техническим.

Ответ 3

Используйте фрагменты кода.

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

В конце концов, эта проблема касается условностей и дисциплины, а не языка. Характер чувствительности к регистру С# и завершение незавершенного кода в Visual Studio - причина, по которой мы делаем эти ошибки, а не отсутствие знаний и дизайна.

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

Для этого в Visual Studio есть фрагмент кода по умолчанию. Введите propfull и нажмите "Tab", затем укажите имя переменной экземпляра и имя свойства, и вам будет удобно идти.

Ответ 4

В некоторых случаях вы не можете обойти сеттеры и геттеры. Но, может быть, вам не нужны сеттеры и геттеры, если вы будете следовать принципу Tell, Do not Ask? В основном он говорит, что предпочитает иметь объект, у которого данные выполняют работу, а не какой-либо другой объектный запрос от объекта данных, принимать решения, а затем записывать данные обратно в объект данных. См. http://martinfowler.com/bliki/TellDontAsk.html

Ответ 5

Не могли бы вы просто написать тест, чтобы покрыть это?

int constructorValue = 4;
TestClass test = new TestClass(constructorValue);
Assert.Equals(test.Test, constructorValue);

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

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

public string Test
{
    get { return _test; }
    set { _test = value; }
}

private string _test;