Почему DateTime.Now является свойством, а не методом?
Прочитав эту запись в блоге: https://web.archive.org/web/20110821003841/http://wekeroad.com:80/post/4069048840/when-should-a-method-be-a-property,
Мне интересно, почему Microsoft выбирает в C#:
DateTime aDt = DateTime.Now;
вместо
DateTime aDt = DateTime.Now();
- Лучшие практики говорят: используйте метод, если дважды вызвать члена подряд, чтобы получить разные результаты
- А также
DateTime.Now
является прекрасным примером недетерминированного метода / свойства.
Знаете ли вы, есть ли причина для такого дизайна?
Или это небольшая ошибка?
6 ответов
Я верю в CLR через C#, Джеффри Рихтер упоминает, что DateTime.Now является ошибкой.
Класс System.DateTime имеет свойство Now только для чтения, которое возвращает текущую дату и время. Каждый раз, когда вы запрашиваете это свойство, оно будет возвращать другое значение. Это ошибка, и Microsoft хочет, чтобы они могли исправить класс, создав метод Now вместо свойства.
CLR via C# 3rd Edition - страница 243
Это на самом деле является детерминированным; его вывод не является случайным, но основан на чем-то вполне предсказуемом.
"Текущее время" все время меняется; чтобы быть относительно "одинаковым" с каждым вызовом, это значение должно меняться, чтобы при каждом вызове возвращалось текущее время.
РЕДАКТИРОВАТЬ:
Это только что произошло со мной: конечно, два последующих вызова метода получения свойства могут возвращать разные результаты, если что-то изменило значение свойства в промежуточный период. Свойства не должны быть Constants
,
Итак, вот что происходит (концептуально) с DateTime.Now
; его значение изменяется между последующими вызовами к нему.
В соответствии с MSDN вы должны использовать свойство, когда что-то является логическим элементом данных объекта:
http://msdn.microsoft.com/en-us/library/bzwdh01d%28VS.71%29.aspx
Далее перечисляем случаи, когда метод будет более подходящим. Ирония заключается в том, что одним из правил метода является его использование, когда последовательные вызовы могут возвращать разные результаты и, конечно, теперь, безусловно, соответствует этим критериям.
Лично я думаю, что это было сделано, чтобы устранить необходимость в дополнительном (), но я обнаружил, что отсутствие () сбивает с толку; мне потребовалось немного времени, чтобы перейти от старого подхода в VB/VBA.
Руководящие принципы - только это, а не жесткие и быстрые правила.
Эти рекомендации предназначены для объектов с состоянием, и в действительности пытаются сказать, что свойства не должны мутировать объект. DateTime.Now является статическим свойством, поэтому его вызов не изменяет объект. Это также просто отражает естественное состояние времени, ничего не меняя. Это просто наблюдение постоянно меняющегося таймера.
Итак, дело в том, что не создавайте свойства, которые изменяют состояние объекта. Создайте свойства, которые просто наблюдают за состоянием объекта (даже если состояние изменяется внешне).
В качестве другого примера, давайте посмотрим на длину строки. Это свойство, но длина строки может изменяться от вызова к вызову, если что-то еще изменяет строку извне. Это в основном то, что происходит, таймер изменяется внешне, теперь просто отражает его текущее состояние так же, как string.Length или любое другое подобное свойство.
При определении "метод в сравнении со свойством", предлагается тест "будут ли последовательные вызовы возвращать разные результаты". Я бы предположил, что лучший тест - это похожий, но не идентичный вопрос: "Повлияет ли вызов подпрограммы на результат будущих вызовов к тем же или другим подпрограммам?" В большинстве случаев ответы на оба вопроса будут одинаковыми, поскольку самой распространенной причиной, по которой последующие вызовы подпрограммы будут приводить к результатам, отличным от предыдущей, является то, что при первом вызове последующий вызов возвращает другое результат, чем это было бы иначе.
В случае DateTime.Now единственным способом, которым один вызов повлияет на значение, возвращаемое другим, было бы, если бы время выполнения, принятое первым вызовом, заставило второй вызов произойти измеримо позже, чем это было бы иначе. В то время как педант может рассматривать течение времени как побочный эффект первого вызова, изменяющий состояние, я бы предположил, что есть много свойств, выполнение которых занимает больше времени, чем DateTime.Now, и, следовательно, вызов любого из них будет иметь большая вероятность изменения значения, возвращаемого последующим вызовом DateTime.Now.
Обратите внимание, что если бы подпрограмма "получить время" была виртуальным членом класса, а не статическим членом, это изменило бы баланс в пользу создания метода; хотя "ожидаемая" реализация не будет влиять на состояние какого-либо объекта, вполне вероятно - или, по крайней мере, правдоподобно - что некоторые реализации могут иметь побочные эффекты. Например, вызов Now для объекта RemoteTimeServer может попытаться получить время от удаленного сервера, и такая попытка может иметь значительные побочные эффекты для остальной системы (например, из-за того, что один или несколько компьютеров будут кэшировать информацию о маршрутизации DNS/IP). так, что следующая попытка доступа к тому же серверу будет завершена на 100 мс быстрее).
Поскольку не существует правил яркой линии относительно того, когда использовать метод и свойство, DateTime.Now действительно просто читает открытое свойство состояния сервера, оно может постоянно изменяться, но DateTime.Now никогда не влияет на состояние какого-либо свойства., объект или что нет, так что это свойство в Framework.