Это неразумно ожидать, что любой () ** не выбрасывать пустой ссылкой исключение?

Когда вы создать метод расширения, вы можете, конечно, называть его на нуль.Но, в отличие от вызова метода экземпляра, называя ее на нуль не'Т У чтобы бросить исключение NullReferenceException -> вы должны проверить и закинуть его вручную.

Для реализации метода расширения LINQ и любой()Microsoft решили, что они должны броситьисключение ArgumentNullException` (https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/AnyAll.cs).

Это раздражает меня, чтобы написать если( моя_коллекция != нуль && коллекции.Любой() )

Я ошибаюсь, как клиент этот код, чтобы ожидать, что, например, ((тип int[])нуль).Любой () должна возвращать значениеfalse`?

Комментарии к вопросу (24)

У меня есть сумка с пятью картофель в нем. Есть .Картофель любой() в мешке?

Yes," Вы говорите. в <= правда

Я беру все из картошки и съесть их. Есть .Картофель любой() в мешке?

но," Вы говорите. в <= ложь

Я полностью испепелить мешок в огонь. Есть `.Картофель любой () в сумке сейчас?

на "There не bag.&и" <= исключение ArgumentNullException

Комментарии (11)

Во-первых, оказывается, что исходный код будет бросать исключение ArgumentNullException, а неисключение NullReferenceException`.

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

я не прав, так как клиент этот код, чтобы ожидать, что, например, ((тип int[])нуль).Любой () должна возвращать значениеfalse`?

Да. Вопрос в том, что любой () ответы есть "Кто эта коллекция содержит каких-либо элементов?" Если этот сборник не существует, то сам вопрос является бессмысленным; он не может ни содержать, ни не содержат ничего, потому что это не'т существуют.

Комментарии (17)

Значение null означает отсутствие информации, не без элементов.

Вы могли бы рассмотреть в более широком контексте, избегая нуль — например, использовать один из встроенных в пустые enumerables, чтобы представить коллекцию без элементов вместо null.

Если вы возвращаете null в некоторых случаях, вы можете изменить это, чтобы вернуть пустой набор&.усилитель;усилитель; nbsp; (иначе, если вы'вновь находить значение null,'ы, возвращаемых методами библиотеки (не ваше), что's несчастливое, и я бы обернуть их в норму.)

См. также https://stackoverflow.com/questions/1191919/what-does-linq-return-when-the-results-are-empty

Комментарии (4)

Помимо нуль-условный синтаксис, есть еще один метод, чтобы устранить эту проблему: Дон'т пусть ваши переменные остаются нуль.

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

public MyResult DoSomething(int a, IEnumerable words)
{
    words = words ?? Enumerable.Empty();

    if (!words.Any())
    {
        ...

Вы можете сделать то же самое, когда вы принести коллекций из другого метода:

var words = GetWords() ?? Enumerable.Empty();

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

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

Комментарии (0)

я не прав, так как клиент этот код, чтобы ожидать, что, например, ((тип int[])нуль).Любой() должна возвращать false?

Да просто потому, что вы're в C# и что поведение четко определены и задокументированы.

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

Лично мне кажется, что возвращать false, это более безопасный подход, что делает вашу программу более надежной, но это's по крайней мере спорно.

Комментарии (5)

Если повторный нуль-проверка раздражать вас, вы можете создать свой собственный 'IsNullOrEmpty()' метод расширения, чтобы отразить метод String с таким именем, и завернуть как null-проверка и .Любой() вызов в одном вызове.

В противном случае, решение, которое было упомянуто @17 из 26 В ответ на свой вопрос, короче 'Стандарт' способ также, и достаточно ясно для тех, кто знаком с новым нуль-условный синтаксис.

if(myCollection?.Any() == true)
Комментарии (7)

я не прав, так как клиент этот код, чтобы ожидать, что, например, ((тип int[])нуль).Любой() должна возвращать false?

Если вам интересно, об ожиданиях вы должны думать о намерениях.

нуль означает что-то очень отличается от перечисли.Пусто в<Т>

Как отмечалось в Эрик Eidt'ы ответ, есть разница в значении между null и пустой набор.

Позвольте's первый взгляд на то, как они должны быть использованы.

Книги рекомендации по проектированию Framework: конвенций, идиомы и шаблоны для многократно используемых .Net библиотеки, 2-й Edition, написанное на Microsoft архитекторов Krzysztof Cwalina и Brad Abrams государств следующие рекомендации:

X не возвращают значения null из коллекции свойств или методов, возвращающих коллекции. Вернет пустой набор или пустой массив.

Рассмотрим ваш вызов метода, в конечном итоге, получение данных из базы данных: Если вы получите пустой массив, или перечисли.Пусто в<Т> Это просто означает, что ваш sample space пуст, т. е. ваш результат-это empty set. Получение нуль в этом контексте, однако, может означать ошибка.

В одной и той же линии мышления Дэн Уилсон'ы аналогию картофеля, имеет смысл задавать вопросы о ваших данных, даже если это empty set. Но это делает много смысла а less, если нет.

Комментарии (5)

Есть много ответов, объясняя, почему null и пустые бывают разные и достаточно мнениями, пытаясь explain, почему они должны относиться по-разному или нет. Однако вы'вновь спрашиваю:

я не прав, так как клиент этот код, чтобы ожидать, что, например, ((тип int[])нуль).Любой() должна возвращать false?

Это'ы совершенно разумные ожидания. Вы'вновь, как right как кто-то еще выступает за нынешнее поведение. Я согласен с нынешней философии внедрения, но и факторы, не только исходя из контекста соображений.

Учитывая, что любой () без предиката это по сути Граф () и gt; 0, тогда чего вы ждете от этого фрагмента?

List list = null;
if (list.Count > 0) {}

Или универсальный:

List list = null;
if (list.Foo()) {}

Я полагаю, что вы ожидаете исключение NullReferenceException.

  • Какие () метод расширения, она должна плавно интегрировать с объектом extended затем бросать исключение составляет не менее удивительное.
  • Не каждый .Net-язык поддерживает методы расширения.
  • Вы всегда можете позвонить перечисли.Любой(нуль) и there вы наверняка ожидаете исключение ArgumentNullException. Это'ы один и тот же метод, и он должен быть в соответствии с - возможно - почти все остальное в рамках.
  • Доступ к "нулевой" объект Программирование ошибки, рамки не должны применять null как магия value. Если вы используете его, то это's ваша ответственность, чтобы справиться с ней.
  • Это'ы самоуверенный, вы думаете так, а я думаю иначе. Основы должно быть столько unopinionated, насколько это возможно.
  • Если у вас особый случай, то вы должны быть в соответствии: вы должны принять все больше и больше очень упрямый решения обо всех других методов расширения: если считать (), кажется легким решением, то где ()- нет. НасчетМакс()? Он бросает исключение для пустой список, разве&#39;т бросить его еще нануль` один?

Какие дизайнеры библиотека сделала перед тем, как LINQ должен был представить явные методы, когда значение null является значением valid (для струнного пример.IsNullOrEmpty ()), то они должны быть в соответствии с существующей философии дизайна. Тем не менее, даже если довольно тривиально, чтобы написать, двух методов EmptyIfNull()иEmptyOrNull()` может пригодиться.

Комментарии (0)

Джим должен оставить картофель в каждую сумку. В противном случае я'м собираешься убить его.

Джим был мешок с пятью картофель в нем. Есть .Картофель любой() в мешке?

"Да," Вы говорите. <= истинное

Итак, Джим живет в этом времени.

Джим забирает всю картошку и ест их. Есть .Любой() картофель в мешке?

"Нет," Вы говорите. <= ложь

Время, чтобы убить Джима.

Джим полностью испепеляет мешок в огонь. Есть .Любой() картофель в сумке сейчас?

на "нет.&и" <= исключение ArgumentNullException

Джим должен жить или умереть? Ну мы не'т ожидать, что это так мне нужно решение. Позволяя Джиму уйти с этой ошибкой или нет?

Вы можете использовать аннотации](https://stackoverflow.com/a/32806406/1493294), чтобы сигнализировать, что вы'повторно не мирятся с нулевой махинации таким способом.

public bool Any( [NotNull] List bag ) 

Но ваша цепочка инструмент для его обслуживания. Значит, вы, скорее всего, все равно выписывает чеки.

Комментарии (0)

Если это беспокоит вас так много, я предлагаю простой метод расширения.

static public IEnumerable NullToEmpty(this IEnumerable source)
{
    return (source == null) ? Enumerable.Empty() : source;
}

Теперь вы можете сделать это:

List list = null;
var flag = list.NullToEmpty().Any( s => s == "Foo" );

...и флаг будет установлен в "false".

Комментарии (3)

Это вопрос о c#'s расширение методов и их философия дизайна, поэтому я думаю, что лучший способ ответить на этот вопрос, это цитата из MSDN's документация на цели расширения methods](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods):

методы расширения позволяют себе "Добавить" и методы в существующие типы без создания нового производного типа, перекомпиляции, или в противном случае изменения исходного типа. Методы расширения-это особый вид статического метода, но они называются так, как если бы они были методами экземпляра на расширенный тип. Для клиентского кода, написанного на C#, F# и Visual основные, нет очевидной разницы между вызовом метода расширения и методы, которые на самом деле являются определенными в виду.

...

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

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

если реализовать методы расширения для данного типа, следует помнить следующие моменты:

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

Подводя итог, методы расширения предназначены для добавления методов экземпляра определенного типа, даже если разработчики не могут сделать это напрямую. И потому, что методы экземпляра будет всегда переопределить методы расширения, если представить (если называют, используя синтаксис обращения к методу экземпляра), это должно быть только делать, если вы не можете напрямую добавить метод или расширить класс.*

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


*В качестве примечания, это как раз та ситуация, что проектировщики LINQ, которая столкнулась: когда в C# 3.0 был выпущен, было уже миллионы клиентов, использующих систему.Коллекции.И система интерфейс IEnumerable`.Коллекции.Универсальный.Интерфейс IEnumerable<Т>, как в их коллекциях и в объекту петли. Эти классы возвращаются интерфейс IEnumerator объекты, которые были только текущие два метода и метода MoveNext, поэтому добавлять любые необходимые дополнительные методы, например, такие какколичество,любой, и т. д., будет нарушать эти миллионы клиентов. Итак, для того, чтобы обеспечить эту функциональность (тем более, что он может быть реализован в условиях нынешнего " и " метод MoveNext с относительной легкостью), они выпустили его, как методы расширения, которые могут быть применены к любой ныне существующей интерфейс IEnumerable экземпляр, а также может быть реализовано путем занятия более эффективными способами. У C#и#39;ы дизайнеры решили выпустить LINQ на один день, он бы, как методы экземпляра интерфейс IEnumerable, и они, вероятно, разработали какую-то систему, чтобы реализовать интерфейс по умолчанию этих методов.

Комментарии (0)

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

Если это's возможные для списка, чтобы быть null, я хотел бы предложить, имеющих отдельного логического пути для этого, поскольку иначе в будущем кто-то может добавить список на основе логики (как дополнение) к другой{} в вашем случае, что приводит к нежелательным исключением, что у них нет оснований прогнозировать.

Читаемость и ремонтопригодность козыри 'я должен написать дополнительное условие' каждый раз.

Комментарии (0)

Как правило, я пишу большинство моих код, чтобы предположить, что вызывающая сторона ответственна за то, что не даешь мне нулевые данные, в основном по причинам, изложенным в Скажи нет нуль (и другие аналогичные должности). Понятие null-это часто не очень хорошо понимают, и по этой причине, это'ы рекомендуется инициализировать переменные загодя, насколько это возможно. Предполагая, что вы'вэ, работающих с разумным API, вы в идеале должны никогда не получают нулевое значение, так что вы никогда не должны проверить на null. Точки нуль, как и другие ответы уже сказал, это чтобы убедиться, что у вас есть действительный объект (например, А "мешок", У), чтобы работать с, Прежде чем продолжить. Это'т функция любой, а особенность язык сам. Вы можете'т делать большинство операций на нулевой объект, потому что его не существует. Это's, как если я попрошу вас подъехать в магазин на моей машине, кроме того, что я Дон'т иметь автомобиль, поэтому у вас нет возможности использовать свой автомобиль, чтобы добраться до магазина. Это'ы бессмысленные выполнить операцию на то, что в буквальном смысле не существует.

Там были представлены практические кейсы по через нуль, например, когда вы буквально не располагает запрашиваемой информацией (например, если бы я спросил Тебя, что мой возраст, наиболее вероятным выбором для вас, чтобы ответить на этот пункт "Я не'т знаю", которая является то, что нулевое значение). Однако, в большинстве случаев, вы должны по крайней мере знать, если ваши переменные инициализируются или нет. И если вы Don't, то я бы рекомендовал вам нужно подтянуть свой код. Самое первое, что я делаю в любой программе или функция для инициализации значение, прежде чем я его использовать. Это редкое, что мне нужно проверить значения null, потому что я могу гарантировать, что мои переменные не равны нулю. Это's не хорошая привычка, чтобы попасть в, и чем чаще вы помните, чтобы инициализировать переменные, тем реже вы должны проверить на null.

Комментарии (0)