Как определить, влияет ли метод расширения на «this» или нет? - PullRequest
4 голосов
/ 20 января 2012

Я знаю, что методы расширения String возвращают String и на самом деле не влияют на переменную, вызывающую метод расширения (поэтому она неизменна) - но как мне узнать, делают ли другие методы расширения или нет? Например, я работаю с List<NewsItem> - и мне нужно упорядочить этот список по убыванию даты, поэтому я написал этот код:

newsItems.OrderByDescending(o => o.Date);

Влияет ли это на список newsItems или просто возвращает IOrderedEnumerable ??

Другими словами, должен ли приведенный выше код действительно читать:

newsItems = newsItems.OrderByDescending(o => o.Date).ToList();

??

Спасибо

Dan

Ответы [ 3 ]

4 голосов
/ 20 января 2012

OrderByDescending - это метод расширения для IEnumerable<T>, который сам обеспечивает доступ только для чтения . Конечно, метод расширения может привести к List<T>, но в основном ни один из методов расширения LINQ to Objects не влияет на их цель (конечно, при условии, что на цели не влияет итерация).

LINQ разработан в функциональном стиле - методы возвращают новое представление данных, а не изменяют цель, к которой они обращаются.

РЕДАКТИРОВАТЬ: Как отметил drew, атрибут [Pure] может быть использован в качестве указания на это, и некоторые инструменты будут его использовать. Тем не менее:

  • Вам все еще нужно верить, что атрибут [Pure] был правильно применен
  • Не всегда легко определить, является ли атрибутом [Pure] (он не отображается в документах, с которыми я связан, например)
  • Вероятно, вам все равно следует читать документацию на все, что вы называете, если вы не уверены в том, что он делает
2 голосов
/ 20 января 2012

Все методы расширения Linq выполняют операции запроса только над последовательностями, поэтому предположим, что они только для чтения (запросы).Таким образом, они возвращают IEnumerable<T> экземпляров, которые предоставляют последовательности значений, представляющих результат операции.

Конечно, ничто не мешает вам создать метод расширения, который модифицирует объект, к которому он применяется (this).

API содержит метаданные, которые в этом случае полезны.Атрибут PureAttribute можно использовать для метода, который не имеет побочных эффектов.Если вы используете инструмент, такой как ReSharper, в своей IDE, он предупредит вас, когда вы попытаетесь вызвать чистый метод и не будете использовать результат.Поскольку такой метод является чистым, он не имеет видимых побочных эффектов в других местах памяти, и поэтому игнорирование результата немного ненормально.Операторы Linq снабжены этим атрибутом.Так это object.ToString() например.Вы также можете использовать этот атрибут в своем собственном коде.

tl; dr R # нашел бы вашу ошибку в этом случае.

0 голосов
/ 20 января 2012

Обычно по параметру (тип значения или ссылочный тип) и, во-вторых, по типу возвращаемого значения.

Если у вас есть сигнатура метода, такая как DateTime DateTime.AddDays(int days), вы получаете два намека на то, что метод не влияет на исходное время даты - во-первых, DateTime является типом значения, во-вторых, он возвращает DateTime. Типы значений, если они изменены в теле метода, будут иметь только свои изменения, примененные локально к копии в стеке. Если тип значения не возвращен, вызывающая сторона никогда не сможет наблюдать эти изменения. Эталонные типы, напротив, могут быть изменены в вызывающем методе и могут иметь изменения, наблюдаемые вызывающей стороной.

Точно так же, если у вас есть метод, такой как IOrderedEnumerable<T> OrderBy(IEnumerable<T> enumerable), несмотря на тот факт, что тип ввода является ссылочным типом (и может быть изменен), намек на то, что при возвращении нового типа оригинал останется неизменным.

Наконец, это может быть подтверждено тестированием. Как общий интерес, все методы расширения цепочки методов LINQ возвращают новый IEnumerable<T>, ленивые вычисляются и не изменяют переданное содержимое IEnumerable<T>, вместо этого применяя фильтр, который оценивается, когда вызывается GetEnumerator возвращенный IEnumerable<T>.

...