Когда вы создаете метод расширения, вы, конечно, можете вызывать его в null
.But, но в отличие от вызова метода экземпляра, для вызова его в null не нужно бросать NullReferenceException
-> вы должны проверять и выбрасывать его вручную.
Для реализации метода расширения Linq Any()
Microsoft решила, что они должны добавить ArgumentNullException
( https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/AnyAll.cs ).
Меня раздражает необходимость писать if( myCollection != null && myCollection.Any() )
Я не прав, как клиент этого кода, ожидать, что, например, ((int[])null).Any()
должен вернуться false
?
c#
.net
linq
extension-method
thisextendsthat
источник
источник
null |> Seq.isEmpty
выбрасываетSystem.ArgumentNullException: Value cannot be null
. Кажется, вы ожидаете, что вы не будете передавать неопределенные значения для чего-то, что, как ожидается, будет существовать, поэтому это все еще исключение, когда у вас есть ноль. Если это вопрос инициализации, я бы начал с пустой последовательности вместоnull
.null
при работе с коллекциями, а вместо этого использовать пустую коллекцию в этих случаях.Any
просто соответствует.Ответы:
У меня есть сумка с пятью картошками. В
.Any()
сумке есть картошка?« Да », говорите вы.
<= true
Я вынимаю всю картошку и ем ее. В
.Any()
сумке есть картошка?« Нет », говорите вы.
<= false
Я полностью сжигаю сумку в огне. В
.Any()
сумке сейчас картошка?" Там нет сумки ".
<= ArgumentNullException
источник
Во-первых, кажется, что этот исходный код будет выбрасывать
ArgumentNullException
, а неNullReferenceException
.Тем не менее, во многих случаях вы уже знаете, что ваша коллекция не равна нулю, потому что этот код вызывается только из кода, который знает, что коллекция уже существует, поэтому вам не нужно будет очень часто ставить там проверку на ноль. Но если вы не знаете, что он существует, то имеет смысл проверить, прежде чем вызывать
Any()
его.Да. Вопрос, который
Any()
отвечает, "содержит ли эта коллекция какие-либо элементы?" Если эта коллекция не существует, то вопрос сам по себе бессмысленный; он не может ни содержать, ни не содержать ничего, потому что он не существует.источник
null
эквивалентен набору, содержащему пустой набор (и наоборот)?{ null }
и{ {} }
должны быть эквивалентны. Я нахожу это захватывающим; Я не могу относиться к этому вообще..Add
наnull
коллекции каким-то образом создать коллекцию и для нас?Нуль означает отсутствие информации, а не элементов.
Вы могли бы более широко избегать нулевого значения - например, используйте один из встроенных пустых перечислимых элементов для представления коллекции без элементов вместо нулевого.
Если вы возвращаете null в некоторых случаях, вы можете изменить это, чтобы вернуть пустую коллекцию. (В противном случае, если вы находите нулевые значения, возвращаемые библиотечными методами (не вашими), это прискорбно, и я бы обернул их для нормализации.)
Смотрите также https://stackoverflow.com/questions/1191919/what-does-linq-return-when-the-results-are-empty
источник
null
не значит, что никакие элементы - это вопрос разумного соглашения. Просто думать о родных OLESTRINGS, где он на самом деле делает в виду.null
не означает «недостающую информацию».null
не имеет ни одного значимого толкования. Вместо этого все зависит от того, как вы к этому относитесь.null
иногда используется для «отсутствующей информации», но также и для «без элементов», а также для «произошла ошибка», «неинициализированной» или «конфликтующей информации» или какой-либо произвольной, специальной вещи.null
Абсолютно часто используется для обозначения «нет данных». Иногда это имеет смысл. В других случаях нет.Помимо условно-нулевого синтаксиса , есть еще один метод, чтобы облегчить эту проблему: не позволяйте вашей переменной остаться
null
.Рассмотрим функцию, которая принимает коллекцию в качестве параметра. Если для целей функции
null
и empty эквивалентны, вы можете убедиться, что он никогда не содержитnull
в начале:Вы можете сделать то же самое, когда извлекаете коллекции из другого метода:
(Обратите внимание , что в тех случаях , когда у вас есть контроль над функцией , как
GetWords
иnull
эквивалентно пустой коллекции, предпочтительно , чтобы просто вернуть пустую коллекцию в первую очередь.)Теперь вы можете выполнить любую операцию по вашему желанию в коллекции. Это особенно полезно, если вам нужно выполнить много операций, которые не будут выполнены, когда выполняется сбор
null
, и в тех случаях, когда вы получите тот же результат, выполнив циклическое выполнение или запрос пустого перечислимого значения, это позволитif
полностью устранить условия.источник
Да, просто потому, что вы находитесь на C #, и это поведение хорошо определено и задокументировано.
Если вы создавали свою собственную библиотеку или использовали другой язык с другой культурой исключений, то было бы разумнее ожидать ложного.
Лично я чувствую, как будто возвращение ложным является более безопасным подходом, который делает вашу программу более надежной, но это спорно, по крайней мере.
источник
Если повторяющиеся проверки на нуль раздражают вас, вы можете создать свой собственный метод расширения IsNullOrEmpty (), чтобы отразить метод String по этому имени и обернуть вызовы null-check и .Any () в один вызов.
В противном случае решение, упомянутое @ 17 из 26 в комментарии к вашему вопросу, будет короче, чем «стандартный» метод, и будет достаточно понятным для любого, кто знаком с новым нулевым условным синтаксисом.
источник
?? false
вместо== true
. Мне бы это показалось более понятным (более чистым), поскольку он обрабатывает только случайnull
, и на самом деле он не является более многословным. Плюс==
проверки на булевы значения обычно вызывают мой рвотный рефлекс. =)myCollection?.Any()
достаточно?myCollection?.Any()
эффективно возвращается булево значение, допускающее nullable, а не обычное логическое значение (то есть bool? Вместо bool). Нет неявного преобразования из bool? к bool, и это bool, который нам нужен в данном конкретном примере (для проверки как частиif
условия). Следовательно, мы должны либо явно сравнивать,true
либо использовать оператор слияния нуля (??).?.
.==
будет ли на самом деле работать. Я уже знаю, что происходит с логическим значением интуитивно, когда оно может быть толькоtrue
илиfalse
; Мне даже не нужно думать об этом. Но бросьтеnull
в смесь, и теперь я должен решить, правильно ли это==
.??
вместо этого просто исключаетсяnull
случай, сокращается его доtrue
иfalse
, что вы уже сразу поняли. Что касается моего рвотного рефлекса, когда я впервые вижу его, мой непосредственный инстинкт - просто удалить его, так как он обычно бесполезен, чего вы не хотите.Если вы задаетесь вопросом об ожиданиях, вы должны думать о намерениях.
null
означает что-то очень отличное отEnumerable.Empty<T>
Как упоминалось в ответе Эрика Эйдта , существует разница в значении между
null
пустой коллекцией.Давайте сначала взглянем на то, как они должны использоваться.
В книге « Рекомендации по проектированию фреймворка: условные обозначения , идиомы и шаблоны для многократно используемых библиотек .NET», 2-е издание, написанное архитекторами Microsoft Кшиштофом Квалиной и Брэдом Абрамсом, изложены следующие рекомендации:
Представьте себе, что вы вызываете метод, который в конечном итоге получает данные из базы данных: если вы получаете пустой массив, или
Enumerable.Empty<T>
это просто означает, что ваше пробное пространство пусто, т.е. ваш результат - пустой набор . Однако получениеnull
в этом контексте означало бы состояние ошибки .В том же смысле, что и картофельная аналогия Дэна Уилсона , имеет смысл задавать вопросы о ваших данных, даже если они пустые . Но это имеет гораздо меньше смысла, если нет набора .
источник
null
и empty может привести к тому же возвращаемому значению для функции, но это не означает, чтоnull
и empty означает абсолютно то же самое в вызывающей области видимости.Есть много ответов, объясняющих, почему
null
и пустые разные, и достаточно мнений, пытающихся объяснить, почему к ним следует относиться по-разному или нет. Однако вы спрашиваете:Это вполне разумное ожидание . Вы так же правы, как кто-то другой, выступающий за нынешнее поведение. Я согласен с нынешней философией реализации, но движущие факторы не только - основаны на соображениях вне контекста.
Учитывая, что
Any()
без предиката, по сути,Count() > 0
то, что вы ожидаете от этого фрагмента?Или общий:
Я полагаю, вы ожидаете
NullReferenceException
.Any()
это метод расширения, он должен плавно интегрироваться с расширенным объектом, тогда выдача исключения - наименее удивительная вещь.Enumerable.Any(null)
и там вы точно ожидаетеArgumentNullException
. Это тот же метод, и он должен соответствовать - возможно - почти ВСЕМУ другому в Framework.null
объекту является ошибкой программирования , фреймворк не должен использовать нулевое значение как магическое значение . Если вы используете это таким образом, то это ваша ответственность, чтобы справиться с этим.Count()
решение кажется легким, тоWhere()
это не так. Как насчетMax()
? Он выбрасывает исключение для ПУСТОГО списка, разве не дляnull
одного?То, что разработчики библиотек делали до LINQ, заключалось в том, чтобы вводить явные методы, когда
null
это допустимое значение (напримерString.IsNullOrEmpty()
), тогда они ДОЛЖНЫ соответствовать существующей философии проектирования . Тем не менее, даже если написать довольно тривиально, два методаEmptyIfNull()
иEmptyOrNull()
могут быть полезны.источник
Джим должен оставлять картошку в каждой сумке. Иначе я его убью.
У Джима есть сумка с пятью картошками. В
.Any()
сумке есть картошка?«Да», говорите вы. <= правда
Итак, Джим живет в этот раз.
Джим достает всю картошку и ест ее. Есть ли в сумке картошка .Any ()?
«Нет», говорите вы. <= ложь
Время убивать Джима.
Джим полностью сжигает сумку в огне. Есть ли в сумке картошка .Any ()?
"Там нет сумки." <= ArgumentNullException
Должен ли Джим жить или умереть? Ну, мы не ожидали этого, поэтому мне нужно решение. Позволить Джиму избежать этой ошибки или нет?
Вы можете использовать аннотации, чтобы сигнализировать, что вы не миритесь с нулевыми махинациями таким образом.
Но ваша цепочка инструментов должна это поддерживать. Что означает, что вы, вероятно, все равно будете в конечном итоге писать чеки.
источник
Если это вас так сильно беспокоит, я предлагаю простой метод расширения.
Теперь вы можете сделать это:
... и флаг будет установлен в
false
.источник
return
заявление как:return source ?? Enumerable.Empty<T>();
Это вопрос о методах расширения C # и их философии проектирования, поэтому я думаю, что лучший способ ответить на этот вопрос - процитировать документацию MSDN о целях методов расширения :
Подводя итог, можно сказать, что методы расширения предназначены для добавления методов экземпляра к определенному типу, даже если разработчики не могут сделать это напрямую. А поскольку методы экземпляра всегда будут переопределять методы расширения, если они есть (если они вызваны с использованием синтаксиса метода экземпляра), это следует делать только в том случае, если вы не можете напрямую добавить метод или расширить класс. *
Другими словами, метод расширения должен действовать точно так же, как и метод экземпляра, поскольку в конечном итоге он может быть создан методом экземпляра некоторым клиентом. И поскольку метод экземпляра должен выдавать, если объект, к которому он вызывается
null
, так же, как и метод расширения.* В качестве дополнительного примечания, именно с такой ситуацией столкнулись дизайнеры LINQ: когда был выпущен C # 3.0, уже были миллионы клиентов, которые использовали
System.Collections.IEnumerable
иSystem.Collections.Generic.IEnumerable<T>
в своих коллекциях, и вforeach
циклах. Эти классы возвращаютсяIEnumerator
объекты , которые были только два методаCurrent
иMoveNext
, таким образом добавляя дополнительные необходимые методы , например, такие , какCount
,Any
и т.д., будет нарушать эти миллионы клиентов. Таким образом, чтобы обеспечить эту функциональность (особенно потому, что она может быть реализована с точки зренияCurrent
иMoveNext
с относительной простотой), они выпустили ее как методы расширения, которые можно применять к любым существующим в настоящее времяIEnumerable
экземпляр и может также быть реализован классами более эффективными способами. Если бы дизайнеры C # решили выпустить LINQ в первый же день, он был бы представлен как методы экземпляраIEnumerable
, и они, вероятно, разработали бы какую-то систему для обеспечения реализаций интерфейса этих методов по умолчанию.источник
Я думаю, что существенным моментом здесь является то, что, возвращая false вместо того, чтобы выдавать исключение, вы запутываете информацию, которая может иметь отношение к будущим читателям / модификаторам вашего кода.
Если список может быть пустым, я бы предложил для этого отдельный логический путь, так как в противном случае кто-то в будущем может добавить некоторую основанную на списке логику (например, добавление) к else {} вашего if, что приведет к нежелательное исключение, что у них нет оснований прогнозировать.
Читаемость и удобство сопровождения превосходят «Я должен написать дополнительное условие» каждый раз.
источник
Как правило, я пишу большую часть своего кода, предполагая, что вызывающая сторона отвечает за то, чтобы не передавать мне нулевые данные, в основном по причинам, изложенным в « Скажи нет пустому» (и другим подобным постам). Концепция нуля часто не совсем понятна, и поэтому желательно инициализировать ваши переменные заранее, насколько это практически возможно. Предполагая, что вы работаете с разумным API, в идеале вы никогда не должны возвращать нулевое значение, поэтому вам никогда не придется проверять нулевое значение. Смысл нуля, как утверждали другие ответы, - это убедиться, что у вас есть действующий объект (например, «сумка») для работы, прежде чем продолжить. Это не особенность
Any
, а особенность языкасам. Вы не можете выполнять большинство операций с нулевым объектом, потому что он не существует. Это как если бы я попросил вас доехать до магазина на моей машине, за исключением того, что у меня нет машины, поэтому у вас нет возможности использовать мою машину, чтобы доехать до магазина. Бессмысленно выполнять операцию над чем-то, что буквально не существует.Существуют практические случаи использования нулевого значения, например, когда у вас буквально нет запрошенной информации (например, если я спросил вас, какого мне возраста, наиболее вероятный вариант ответа на этот вопрос - «Я не знаю»). ", что является нулевым значением). Однако в большинстве случаев вы должны хотя бы знать, инициализированы ли ваши переменные или нет. А если нет, то я бы порекомендовал вам ужесточить свой код. Самое первое, что я делаю в любой программе или функции, это инициализирую значение перед тем, как его использовать. Редко мне нужно проверять наличие нулевых значений, потому что я могу гарантировать, что мои переменные не равны нулю. Это хорошая привычка, и чем чаще вы не забываете инициализировать свои переменные, тем реже вам нужно проверять наличие нуля.
источник