Должны ли свойства иметь побочные эффекты


19

Должны ли свойства в C # иметь побочные эффекты помимо уведомления об изменении его состояний?

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


3
Ах, позвольте мне найти соответствующий ТАК вопрос. 1 секунда stackoverflow.com/questions/2451910/… stackoverflow.com/questions/2784934/… stackoverflow.com/questions/582680/… stackoverflow.com/questions/694711/…
Работа

1
Среди выводов @ Job, почему я должен избегать использования свойств в C #? Мнение Джеффри Рихтера очень относится к этому вопросу.
Rwong

@rwong Относительно да, но совершенно бессмысленно - тем не менее, нужно читать (чтобы знать о проблемах, которые он выделяет). По крайней мере, по этому вопросу я нахожусь в лагере скитов.
Апурв Хурасия

Хотя это относится к конструкторам, это также имеет отношение: programmers.stackexchange.com/a/164255/1996
Джим Г.

Ответы:


40

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

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

В общем , это означает, что получатели свойства не должны иметь побочных эффектов.

Однако давайте будем осторожны с тем, что мы подразумеваем под «побочным эффектом».

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

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

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

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

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

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


2
+1 - хороший полный ответ, включающий более сложные случаи, которые превращают «должен» в «должен… кроме случаев, когда…»
quick_now

Еще один пример приемлемого побочного эффекта для геттера: функция регистрации.
Лорен Печтел

5

Я отвечу на ваш вопрос вопросом: что происходит, когда вы изменяете свойство Width формы?

Просто из головы, это будет:

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

(Отказ от ответственности: я разработчик Delphi, а не разработчик .NET. Возможно, это не на 100% точно для C #, но я уверен, что это довольно близко, особенно если учесть, сколько исходной платформы .NET было основано на Delphi.)

Все эти «побочные эффекты» возникают при изменении свойства Width на форме. Кто-то из них кажется неуместным или неправильным?


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

5

Взгляните на правила разработки Microsoft , особенно на одно из них:

CA1024: Используйте свойства, где это уместно

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

  • Не принимает аргументов и возвращает информацию о состоянии объекта.
  • Принимает один аргумент для установки некоторой части состояния объекта.

Свойства должны вести себя так, как будто они являются полями; если метод не может, он не должен быть изменен на свойство. Методы лучше, чем свойства в следующих ситуациях:

  • Метод выполняет трудоемкую операцию. Метод заметно медленнее, чем время, необходимое для установки или получения значения поля.
  • Метод выполняет преобразование. Доступ к полю не возвращает преобразованную версию данных, которые оно хранит.
  • Метод Get имеет заметный побочный эффект. Получение значения поля не вызывает никаких побочных эффектов.
  • Порядок исполнения важен. Установка значения поля не зависит от появления других операций.
  • Вызов метода два раза подряд создает разные результаты.
  • Метод является статическим, но возвращает объект, который может быть изменен вызывающей стороной. Получение значения поля не позволяет вызывающей стороне изменять данные, которые хранятся в этом поле.
  • Метод возвращает массив ...

2

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

РЕДАКТИРОВАТЬ : О, еще одна вещь - запуск события, говоря «PropertyXYZ Изменен!» (например INotifyPropertyChanged) - хорошо для сеттеров.


2

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


2

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

  1. Мы хотим, чтобы классы были легко тестируемыми.
  2. Мы хотим, чтобы классы поддерживали параллелизм
  3. Мы хотим, чтобы уроки были понятны для третьих лиц

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

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

Большой вопрос, вероятно, предназначен для людей, которые относятся к вашему классу как к «черному ящику». Было бы нелегко узнать, что какое-то состояние изменилось только из-за того, что они прочитали свойство или что какое-то другое свойство изменяется из-за другого изменения (которое может привести каскадным обновлениям).

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.