[英]Does C# have IsNullOrEmpty for List/IEnumerable?
我知道通常空列表比 NULL 更可取。 但我要返回 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();
}
出於性能原因,Daniel Vaughan 采取了額外的步驟,即強制轉換為 ICollection(在可能的情況下)。 我不會想到要做的事情。
后期更新:從 C# 6.0 開始,可以使用空傳播運算符來表達簡潔,如下所示:
if ( list?.Count > 0 ) // For List<T>
if ( array?.Length > 0 ) // For Array<T>
或者,作為IEnumerable<T>
的更清潔和更通用的替代方案:
if ( enumerable?.Any() ?? false )
注意 1:與 OP 問題(引用)相反,所有上層變體實際上都反映IsNotNullOrEmpty
:
由於運算符優先級,
IsNullOrEmpty
等效項看起來不那么吸引人:
if (!(list?.Count > 0))
注2: ?? false
?? false
是必要的,因為以下原因( 此帖子的摘要/引用):
?.
如果子成員為null
null
但是 [...] 如果我們嘗試獲取一個非Nullable
成員,例如Any()
方法,它返回bool
[...] 編譯器將在Nullable<>
中“包裝”一個返回值。 例如,Object?.Any()
會給我們bool?
(這是Nullable<bool>
),而不是bool
。 [...] 因為它不能被隱式轉換為bool
,所以這個表達式不能在if
中使用
注 3:作為獎勵,該語句也是“線程安全的”(引自 answer of this question ):
在多線程上下文中,如果 [ enumerable ] 可以從另一個線程訪問(因為它是一個可訪問的字段,或者因為它在暴露給另一個線程的 lambda 中被關閉),那么每次計算時值可能不同 [ ieprior null -檢查]
沒有內置任何東西。
這是一個簡單的擴展方法:
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()
調用將“忘記”一個元素。
您可以采取不同的方法並將空值變成空值:
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()
等。
我修改了 Matthew Vines 的建議以避免“IEnumerable 的可能多重枚舉”問題。 (另見 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());
}
var nullOrEmpty = !( list?.Count > 0 );
對我來說最好的 isNullOrEmpty 方法看起來像這樣
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
return !enumerable?.Any() ?? true;
}
public static class IEnumerableExtention
{
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
if (enumerable == null)
{
return true;
}
using var enumerator = enumerable.GetEnumerator();
var isEmpty = !enumerator.MoveNext();
return isEmpty;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.