一般に、空のリストの方がNULLよりも望ましいことを知っています。ただし、主に2つの理由から、NULLを返します。
??
操作後、戻り値を取得します。文字列の場合、IsNullOrEmptyがあります。 C#自体から ListまたはIEnumerableに対して同じことをしていますか?
フレームワークに焼き付けられたものは何もありませんが、それは非常に単純な拡張メソッドです。
/// <summary>
/// Determines whether the collection is null or contains no elements.
/// </summary>
/// <typeparam name="T">The IEnumerable type.</typeparam>
/// <param name="enumerable">The enumerable, which may be null or empty.</param>
/// <returns>
/// <c>true</c> if the IEnumerable is null or empty; otherwise, <c>false</c>.
/// </returns>
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
if (enumerable == null)
{
return true;
}
/* If this is a list, use the Count property for efficiency.
* The Count property is O(1) while IEnumerable.Count() is O(N). */
var collection = enumerable as ICollection<T>;
if (collection != null)
{
return collection.Count < 1;
}
return !enumerable.Any();
}
ダニエルヴォーンは、パフォーマンス上の理由からICollection(可能な場合)にキャストする追加の手順を実行します。私がやろうとは思わなかったことでしょう。
後期更新:C#6.0以降、null-propagation operatorを使用してこのように簡潔に表現できます:
_if (enumerable?.Any() ?? false)
_
注1:_?? false
_は、次の理由のために必要です( この投稿 )からの要約/引用):
_
?.
_演算子は、子メンバーがnull
の場合、null
を返します。 [...]Nullable
[...]を返すAny()
メソッドのような非bool
メンバーを取得しようとすると、コンパイラは " _Nullable<>
_で戻り値をラップします。たとえば、Object?.Any()
は、bool
ではなく、_bool?
_(_Nullable<bool>
_)を返します。 [...]暗黙的にbool
にキャストできないため、この式はif
で使用できません
注2:ボーナスとして、ステートメントは「スレッドセーフ」です( この質問 の回答からの引用):
マルチスレッドコンテキストで、[enumerable]が別のスレッドからアクセス可能な場合(アクセス可能なフィールドであるか、別のスレッドに公開されているラムダで閉じられているため)値は計算されるたびに異なる可能性があります[ieprior null-check]
何も組み込まれていません。
ただし、これは単純な拡張メソッドです。
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
if(enumerable == null)
return true;
return !enumerable.Any();
}
var nullOrEmpty = list == null || !list.Any();
上記の回答をC#6.0+の簡単な拡張メソッドにまとめます。
public static bool IsNullOrEmpty<T>(this IEnumerable<T> me) => !me?.Any() ?? true;
他の誰もが言ったように、フレームワークには何も組み込まれていませんが、Castleを使用している場合、Castle.Core.Internalにはそれがあります。
using Castle.Core.Internal;
namespace PhoneNumbers
{
public class PhoneNumberService : IPhoneNumberService
{
public void ConsolidateNumbers(Account accountRequest)
{
if (accountRequest.Addresses.IsNullOrEmpty()) // Addresses is List<T>
{
return;
}
...
空でない場合にすべての要素を取得できるようにする必要がある場合、巻き戻し不可能な列挙型のAny()
の呼び出しは要素を「忘れる」。
別のアプローチを取り、nullを空に変えることもできます。
bool didSomething = false;
foreach(var element in someEnumeration ?? Enumerable.Empty<MyType>())
{
//some sensible thing to do on element...
didSomething = true;
}
if(!didSomething)
{
//handle the fact that it was null or empty (without caring which).
}
同様に(someEnumeration ?? Enumerable.Empty<MyType>()).ToList()
などを使用できます。
var nullOrEmpty = !( list?.Count > 0 );
私にとって最高のisNullOrEmptyメソッドは次のようになります
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
return !enumerable?.Any() ?? true;
}
「IEnumerableの可能な複数列挙」問題を回避するために、Matthew Vinesからの提案を修正しました。 (Jon Hannaからのコメントも参照)
public static bool IsNullOrEmpty(this IEnumerable items)
=> items == null
|| (items as ICollection)?.Count == 0
|| !items.GetEnumerator().MoveNext();
...および単体テスト:
[Test]
public void TestEnumerableEx()
{
List<int> list = null;
Assert.IsTrue(list.IsNullOrEmpty());
list = new List<int>();
Assert.IsTrue(list.IsNullOrEmpty());
list.AddRange(new []{1, 2, 3});
Assert.IsFalse(list.IsNullOrEmpty());
var enumerator = list.GetEnumerator();
for(var i = 1; i <= list.Count; i++)
{
Assert.IsFalse(list.IsNullOrEmpty());
Assert.IsTrue(enumerator.MoveNext());
Assert.AreEqual(i, enumerator.Current);
}
Assert.IsFalse(list.IsNullOrEmpty());
Assert.IsFalse(enumerator.MoveNext());
}