私はstring.IsNullOrEmpty
方法が大好きです。IEnumerableに同じ機能を許可するものが欲しいです。そのようなものはありますか?たぶんコレクションヘルパークラス?私が尋ねる理由は、if
ステートメントでは、パターンがそうだとコードが乱雑に見えるからです(mylist != null && mylist.Any())
。持つ方がはるかにクリーンになりますFoo.IsAny(myList)
。
この投稿はその答えを与えません:IEnumerableは空ですか?。
私はstring.IsNullOrEmpty
方法が大好きです。IEnumerableに同じ機能を許可するものが欲しいです。そのようなものはありますか?たぶんコレクションヘルパークラス?私が尋ねる理由は、if
ステートメントでは、パターンがそうだとコードが乱雑に見えるからです(mylist != null && mylist.Any())
。持つ方がはるかにクリーンになりますFoo.IsAny(myList)
。
この投稿はその答えを与えません:IEnumerableは空ですか?。
回答:
確かにあなたはそれを書くことができます:
public static class Utils {
public static bool IsAny<T>(this IEnumerable<T> data) {
return data != null && data.Any();
}
}
ただし、すべてのシーケンスが反復可能であるとは限らないことに注意してください。一般的に、念のために一度だけ歩くことを好みます。
this
そこを落とします-私null
は醜いデザインのしるしとして呼ばれると想定される拡張メソッドを考えます。
.Any()
は、動作する拡張メソッドですIEnumerable<T>
(またはIQueryable<T>
、これは別のシナリオですが)。そうすることで、少なくとも部分的にシーケンスを消費します(ただし、それでも消費されることを意味します)。1つの要素を読み取るだけで十分な場合があります(特に述語がない場合)。そのため、シーケンス(IEnumerable<T>
)は反復可能である必要はないので、それだけかもしれません。Any()
述語なしの場合は、コンパイラ構文の代わりにetcを使用しますが、基本的に同等ですforeach(var x in sequence) { return true; } return false;
GetEnumerator()
これは、静的ラッパークラスを含む、@ Matt Greerの便利な回答の変更バージョンです。これにより、これを新しいソースファイルにコピーアンドペーストでき、Linqに依存せず、一般的なIEnumerable<T>
オーバーロードを追加して、値型のボックス化を回避できます。これは、非ジェネリックバージョンで発生します。[編集:の使用はIEnumerable<T>
列挙子のボックス化を妨げないことに注意してください。ダックタイピングはそれを防ぐことはできませんが、少なくとも値型コレクションの要素はそれぞれボックス化されません。]
using System.Collections;
using System.Collections.Generic;
public static class IsNullOrEmptyExtension
{
public static bool IsNullOrEmpty(this IEnumerable source)
{
if (source != null)
{
foreach (object obj in source)
{
return false;
}
}
return true;
}
public static bool IsNullOrEmpty<T>(this IEnumerable<T> source)
{
if (source != null)
{
foreach (T obj in source)
{
return false;
}
}
return true;
}
}
もう1つの方法は、Enumeratorを取得してMoveNext()メソッドを呼び出し、アイテムがあるかどうかを確認することです。
if (mylist != null && mylist.GetEnumerator().MoveNext())
{
// The list is not null or empty
}
これは、IEnumerableおよびIEnumerable <T>で機能します。
IEnumerable<T>
非ジェネリックIEnumerable
は実装していないため、ステートメントはに対してのみ真であることに注意してくださいIDisposable
。
私のやり方は、いくつかの最新のC#機能を利用しています。
オプション1)
public static class Utils {
public static bool IsNullOrEmpty<T>(this IEnumerable<T> list) {
return !(list?.Any() ?? false);
}
}
オプション2)
public static class Utils {
public static bool IsNullOrEmpty<T>(this IEnumerable<T> list) {
return !(list?.Any()).GetValueOrDefault();
}
}
ちなみに、コレクションが空かどうかを確認しCount == 0
たり、使用したりしCount() == 0
ないでください。常にLinqを使用する.Any()
!
特に2番目のオプションで、読み取り不能な否定演算子がどのように使用できるかを示す良い例;)
これは役立つかもしれません
public static bool IsAny<T>(this IEnumerable<T> enumerable)
{
return enumerable?.Any() == true;
}
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
return enumerable?.Any() != true;
}
C#6以降では、null伝播を使用できます。myList?.Any() == true
それでもこれがわかりづらい、または古き良き拡張方法を好む場合は、マットグリアとマークグラベルの回答をお勧めします。
彼らの答えは同じ基本機能を提供しますが、それぞれ別の観点からです。マットの答えはstring.IsNullOrEmpty
-mentalityを使用していますが、マルクの答えはLinqの答えを取ります.Any()
が仕事を道をます。
私は個人的に.Any()
道路を使用する傾向がありますが、メソッドの他のオーバーロードから条件チェック機能を追加したいと思います:
public static bool AnyNotNull<T>(this IEnumerable<T> source, Func<T, bool> predicate = null)
{
if (source == null) return false;
return predicate == null
? source.Any()
: source.Any(predicate);
}
だから、あなたはまだのようなmyList.AnyNotNull(item=>item.AnswerToLife == 42);
ことをすることができます:通常と同じように
.Any()
、追加されたnullチェックで
なお、C#6の方法と:myList?.Any()
戻るbool?
のではなくbool
、実際の効果であり、伝搬ヌル
以下は、Marc Gravellの回答のコードと、その使用例です。
using System;
using System.Collections.Generic;
using System.Linq;
public static class Utils
{
public static bool IsAny<T>(this IEnumerable<T> data)
{
return data != null && data.Any();
}
}
class Program
{
static void Main(string[] args)
{
IEnumerable<string> items;
//items = null;
//items = new String[0];
items = new String[] { "foo", "bar", "baz" };
/*** Example Starts Here ***/
if (items.IsAny())
{
foreach (var item in items)
{
Console.WriteLine(item);
}
}
else
{
Console.WriteLine("No items.");
}
}
}
彼が言うように、すべてのシーケンスが反復可能であるとは限らないためIsAny()
、シーケンスをステップ実行し始めるため、コードが問題を引き起こす可能性があります。Robert Harveyの答えが何を意味していたかは、多くの場合、チェックしnull
て空にする必要がないことだと思います。多くの場合、nullを確認してから使用できますforeach
。
シーケンスの2回の開始を回避してを利用するためにforeach
、次のようなコードを記述しました。
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
IEnumerable<string> items;
//items = null;
//items = new String[0];
items = new String[] { "foo", "bar", "baz" };
/*** Example Starts Here ***/
bool isEmpty = true;
if (items != null)
{
foreach (var item in items)
{
isEmpty = false;
Console.WriteLine(item);
}
}
if (isEmpty)
{
Console.WriteLine("No items.");
}
}
}
拡張メソッドを使用すると、数行入力する手間が省けると思いますが、このコードの方がわかりやすいようです。一部の開発者は、それIsAny(items)
が実際にシーケンスをステップし始めることにすぐには気付かないでしょう。(もちろん、多くのシーケンスを使用している場合は、それらをどのステップで実行するかについて考えることをすぐに学びます。)
使用しますBool IsCollectionNullOrEmpty = !(Collection?.Any()??false);
。お役に立てれば。
壊す:
Collection?.Any()
null
コレクションがnullのfalse
場合、およびコレクションが空の場合に返されます。
Collection?.Any()??false
私たちを与えるfalse
コレクションが空の場合、およびfalse
コレクションがある場合null
。
それを補完してくれIsEmptyOrNull
ます。
Jon Skeetのanwser(https://stackoverflow.com/a/28904021/8207463)は、拡張メソッド-Any ()をNULLとEMPTYに使用する優れたアプローチを持っています。しかし、彼はNOT NULLの場合に備えて質問の所有者を検証しています。したがって、JonのアプローチをAS NULLを検証するように慎重に変更します。
If (yourList?.Any() != true)
{
..your code...
}
使用しないでください(AS NULLは検証されません):
If (yourList?.Any() == false)
{
..your code...
}
AS NOT NULLを検証する場合(例としてはテストされていませんが、コンパイラエラーなし)、述語を使用するようなこともできます。
If (yourList?.Any(p => p.anyItem == null) == true)
{
..your code...
}
https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,8788153112b7ffd0
使用できる.NETバージョンについては、次を確認してください。
私は同じ問題を抱えており、私はそれを次のように解決します:
public bool HasMember(IEnumerable<TEntity> Dataset)
{
return Dataset != null && Dataset.Any(c=>c!=null);
}
「c => c!= null」はすべてのnullエンティティを無視します。
私は@Matt Greerの回答からこれを構築しました
彼はOPの質問に完璧に答えました。
Anyの元の機能を維持しながら、nullもチェックしながら、このようなものが欲しかった。他の誰かが同様の何かを必要とする場合に備えて、これを投稿しています。
具体的には、私はまだ述語を渡すことができるようにしたかったのです。
public static class Utilities
{
/// <summary>
/// Determines whether a sequence has a value and contains any elements.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <param name="source">The <see cref="System.Collections.Generic.IEnumerable"/> to check for emptiness.</param>
/// <returns>true if the source sequence is not null and contains any elements; otherwise, false.</returns>
public static bool AnyNotNull<TSource>(this IEnumerable<TSource> source)
{
return source?.Any() == true;
}
/// <summary>
/// Determines whether a sequence has a value and any element of a sequence satisfies a condition.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <param name="source">An <see cref="System.Collections.Generic.IEnumerable"/> whose elements to apply the predicate to.</param>
/// <param name="predicate">A function to test each element for a condition.</param>
/// <returns>true if the source sequence is not null and any elements in the source sequence pass the test in the specified predicate; otherwise, false.</returns>
public static bool AnyNotNull<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
return source?.Any(predicate) == true;
}
}
拡張メソッドの命名はおそらくもっと良いでしょう。
空かどうかをチェックする以下のような他の最良の解決策はありますか?
for(var item in listEnumerable)
{
var count=item.Length;
if(count>0)
{
// not empty or null
}
else
{
// empty
}
}
listEnumerable
手元の問題であるnullである場合、それは機能しません
1回の読み取りでいくつかのリソースが使い果たされるので、従来の個別のチェックではなく、チェックと読み取りを組み合わせてから、読み取りを実行してみませんか。
最初に、より単純なnullのチェックのインライン拡張用の1つがあります。
public static System.Collections.Generic.IEnumerable<T> ThrowOnNull<T>(this System.Collections.Generic.IEnumerable<T> source, string paramName = null) => source ?? throw new System.ArgumentNullException(paramName ?? nameof(source));
var first = source.ThrowOnNull().First();
次に、もう少し複雑になります(少なくとも、私が書いた方法で)、null-and-emptyのインライン拡張をチェックします。
public static System.Collections.Generic.IEnumerable<T> ThrowOnNullOrEmpty<T>(this System.Collections.Generic.IEnumerable<T> source, string paramName = null)
{
using (var e = source.ThrowOnNull(paramName).GetEnumerator())
{
if (!e.MoveNext())
{
throw new System.ArgumentException(@"The sequence is empty.", paramName ?? nameof(source));
}
do
{
yield return e.Current;
}
while (e.MoveNext());
}
}
var first = source.ThrowOnNullOrEmpty().First();
もちろん、コールチェーンを継続せずに両方を呼び出すこともできます。また、paramNameを含めたので、「nameof(target)」などの「ソース」がチェックされていない場合に、呼び出し元がエラーの代替名を含めることができます。
カスタムヘルパーがない?.Any() ?? false
場合?.Any() == true
は、どちらか、または比較的簡潔で、シーケンスを1回指定するだけで済むことをお勧めします。
不足しているコレクションを空のコレクションのように扱いたい場合は、次の拡張メソッドを使用します。
public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T> sequence)
{
return sequence ?? Enumerable.Empty<T>();
}
この関数はforeach
、だけでなく、すべてのLINQメソッドと組み合わせることができます.Any()
。そのため、ここで人々が提案しているより専門的なヘルパー関数よりもこの関数を好みます。
このオープンソースライブラリを見てみましょう:Nzr.ToolBox
public static bool IsEmpty(this System.Collections.IEnumerable enumerable)
それをチェックする場合、私は単純に使用しました
私の解決策をチェックしてください
foreach (Pet pet in v.Pets)
{
if (pet == null)
{
Console.WriteLine(" No pet");// enumerator is empty
break;
}
Console.WriteLine(" {0}", pet.Name);
}