¿Tiene C#IsNullOrEmpty para List/IEnumerable?
(9)
Sé que generalmente la lista vacía es más preferible que NULL. Pero voy a devolver NULL, principalmente por dos razones
- Debo verificar y manejar valores nulos explícitamente, evitando errores y ataques.
- Es fácil de realizar
??
operación posterior para obtener un valor de retorno.
Para cadenas, tenemos IsNullOrEmpty. ¿Hay algo desde C # que haga lo mismo para List o IEnumerable?
Como todos han dicho, nada está incorporado en el marco, pero si estás usando Castle entonces Castle.Core.Internal lo tiene.
using Castle.Core.Internal;
namespace PhoneNumbers
{
public class PhoneNumberService : IPhoneNumberService
{
public void ConsolidateNumbers(Account accountRequest)
{
if (accountRequest.Addresses.IsNullOrEmpty()) // Addresses is List<T>
{
return;
}
...
Modifiqué la sugerencia de Matthew Vines para evitar la "Enumeración múltiple posible de IEnumerable" - problema. (ver también el comentario de Jon Hanna)
public static bool IsNullOrEmpty(this IEnumerable items)
=> items == null
|| (items as ICollection)?.Count == 0
|| !items.GetEnumerator().MoveNext();
... y la prueba de unidad:
[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());
}
No hay nada incorporado
Sin embargo, es un método de extensión simple:
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
if(enumerable == null)
return true;
return !enumerable.Any();
}
Si necesita poder recuperar todos los elementos en caso de que no estén vacíos, algunas de las respuestas aquí no funcionarán, porque la llamada a Any()
en un enumerable no rewindable "olvidará" un elemento.
Podría tomar un enfoque diferente y convertir los valores nulos en vacíos:
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).
}
Del mismo modo (someEnumeration ?? Enumerable.Empty<MyType>()).ToList()
etc.
Uniendo las respuestas anteriores en un método de extensión simple para C # 6.0+:
public static bool IsNullOrEmpty<T>(this IEnumerable<T> me) => !me?.Any() ?? true;
nada en el marco, pero es un método de extensión bastante directo.
/// <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 da el paso extra de lanzar a ICollection (donde sea posible) por motivos de rendimiento. Algo que no hubiera pensado hacer.
Actualización tardía : desde C # 6.0, el operador de propagación nula se puede usar para expresar concisión como esta:
if (enumerable?.Any() ?? false)
Nota 1: ?? false
?? false
es necesario, por el siguiente motivo (resumen / cita de esta publicación ):
?.
el operador devolveránull
si un miembro hijo esnull
. Pero [...] si intentamos obtener un miembro que no seaNullable
, como el métodoAny()
, que devuelvebool
[...] el compilador "ajustará" un valor de retorno enNullable<>
. Por ejemplo,Object?.Any()
nos darábool?
(que esNullable<bool>
), nobool
. [...] Dado que no se puede convertir implícitamente enbool
esta expresión no se puede usar en elif
Nota 2: como una bonificación, la declaración también es "thread-safe" (cita de la respuesta de esta pregunta ):
En un contexto multiproceso, si se puede acceder a [ enumerable ] desde otro subproceso (ya sea porque es un campo accesible o porque está cerrado en un lambda que está expuesto a otro subproceso), el valor podría ser diferente cada vez que se compute [ ieprior null -check ]
var nullOrEmpty = !( list?.Count > 0 );
var nullOrEmpty = list == null || !list.Any();