Есть несколько подобных вопросов, которые касаются правильных типов ввода и вывода , таких как. Мой вопрос заключается в том, какие передовые практики, присвоение имен методам, выбор типа параметров и т.п. Могут защитить от аварий с отложенным выполнением?
Они наиболее распространены в IEnumerable
, который является очень распространенным типом аргумента, потому что:
Следует принципу надежности "Будьте консервативны в том, что вы делаете, будьте либеральными в том, что вы принимаете от других"
Широко используется с
Linq
IEnumerable
занимает высокое место в иерархии коллекций и предшествует новым типам коллекций
Однако, это также вводит отложенное выполнение. Теперь мы могли ошибаться при разработке наших методов (особенно методов расширения), когда думали, что лучшая идея - выбрать самый простой тип. Итак, наши методы выглядят так:
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> lstObject)
{
foreach (T t in lstObject)
//some fisher-yates may be
}
Опасность, очевидно, заключается в том, что мы смешиваем вышеуказанную функцию с ленивой Linq
и настолько восприимчивой.
var query = foos.Select(p => p).Where(p => p).OrderBy(p => p); //does not execute
//but
var query = foos.Select(p => p).Where(p => p).Shuffle().OrderBy(p => p);
//the second line executes up to a point.
Большая правка:
Повторное открытие этого: критика языковой функциональности не конструктивна - однако спрос на передовую практику - вот где сияет Кару. Обновлен вопрос, чтобы отразить это.
Большое редактирование здесь:
Чтобы прояснить вышеприведенную строку - мой вопрос не о том, что второе выражение не оценивается, серьезно нет. Программисты это знают. Меня беспокоит метод TG46, который на самом деле выполняет запрос до этого момента. Смотрите первый запрос, где ничего не выполняется. Теперь аналогичным образом при создании другого выражения Linq (которое должно быть выполнено позже) наша пользовательская функция воспроизводит спойлспорт. Другими словами, как сообщить вызывающему Shuffle
, это не та функция, которую они хотели бы получить в этот момент выражения Linq. Я надеюсь, что дело дошло до дома. Извиняюсь! :) Хотя это так же просто, как проверить и изучить метод, я спрашиваю, как вы, ребята, обычно программируете в обороне...
Приведенный выше пример может быть не таким опасным, но вы понимаете, в чем суть. То есть определенные (пользовательские) функции не соответствуют идее Linq
об отложенном выполнении. Проблема не только в производительности, но и в неожиданных побочных эффектах.
Но такая функция работает волшебно с Linq
:
public static IEnumerable<S> DistinctBy<S, T>(this IEnumerable<S> source,
Func<S, T> keySelector)
{
HashSet<T> seenKeys = new HashSet<T>(); //credits Jon Skeet
foreach (var element in source)
if (seenKeys.Add(keySelector(element)))
yield return element;
}
Как вы можете видеть, обе функции принимают IEnumerable<>
, но вызывающая сторона не знает, как эти функции реагируют. Каковы общие меры предосторожности, которые вы, ребята, принимаете здесь?
Назовите наши пользовательские методы соответствующим образом, чтобы у вызывающей стороны было представление о том, хорошо ли это работает или нет
Linq
?Переместите ленивые методы в другое пространство имен и оставьте
Linq
-ish в другое, чтобы это хотя бы дало какую-то идею?Не принимаете
IEnumerable
в качестве параметра для методов выполненияimmediately
, а вместо этого выбираете более производный тип или конкретный тип, который, таким образом, оставляетIEnumerable
только для ленивых методов? Это возлагает на вызывающего абонента бремя выполнения возможных невыполненных выражений? Это вполне возможно для нас, поскольку за пределами мираLinq
мы почти не имеем дело сIEnumerable
, и большинство базовых классов коллекций реализуют, по крайней мере, доICollection
.
Или что-нибудь еще? Мне особенно нравится 3-й вариант, и это то, что я собирался, но подумал, чтобы получить ваши идеи до. Я видел много кода (миленький Linq
, например, методы расширения!) Даже от хороших программистов, которые принимают IEnumerable
и делают ToList()
или что-то похожее внутри них внутри метода. Я не знаю, как они справляются с побочными эффектами..
Редактировать: После понижения и ответа я хотел бы уточнить, что речь идет не о программистах, не знающих о том, как работает Linq (наш уровень может быть на некотором уровне, но это совсем другое), а о том, что многие функции были написано не принимая во внимание Linq тогда. Теперь связывание сразу выполняющегося метода с методами расширения Linq делает его опасным. Итак, мой вопрос: есть ли общие правила, которым следуют программисты, чтобы сообщить вызывающей стороне, что использовать со стороны Linq, а что нет? Это больше о программировании для защиты, чем если вы не знаете, как использовать то, тогда мы не можем помочь! (или, по крайней мере, я верю)..