Есть несколько вопросов, подобных этому, которые касаются правильных типов ввода и вывода вот так. Мой вопрос заключается в том, какие передовые методы, именование методов, выбор типа параметра или подобное могут защитить от аварий с отложенным выполнением?
Они наиболее распространены с 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); //doesn't execute
//but
var query = foos.Select(p => p).Where(p => p).Shuffle().OrderBy(p => p);
//the second line executes up to a point.
Большая редакция:
Повторное открытие: критика функциональности языка неконструктивна, однако спрашивать о передовом опыте — вот где сияет StackOverflow. Обновил вопрос, чтобы отразить это.
Большое редактирование здесь:
Чтобы уточнить приведенную выше строку. Мой вопрос не о том, что второе выражение не оценивается, серьезно. Программисты это знают. Меня беспокоит метод Shuffle
, фактически выполняющий запрос до этого момента. См. первый запрос, в котором ничего не выполняется. Теперь аналогичным образом при построении другого выражения 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, а что нет? Это больше относится к оборонительному программированию, чем если-вы-не-знаете-использовать-это-то-мы-не-можем-помочь! (по крайней мере, я так думаю)..
MoveNext()
. Всегда можно было написать это вручную, и компилятор C# сделает это за вас с помощью ключевого словаyield
. - person SLaks   schedule 26.11.2012yield
. Хм, так что я считаю, что этот вопрос все еще актуален, учитывая, что Linq сделал его таким распространенным. Просто пытаюсь увидеть, как люди пишут собственные методы, которые должны будут иметь дело с Linq. - person nawfal   schedule 26.11.2012ToList()
илиToArray()
, чтобы заставить это поведение - я признаю, что это не идеально. - person SAJ14SAJ   schedule 26.11.2012