c# - elementat - ¿Cómo obtengo el primer elemento de un IEnumerable<T> en.net?
elementat c# (8)
Bueno, no especificaste qué versión de .Net estás usando.
Suponiendo que tiene 3.5, otra forma es el método ElementAt:
var e = enumerable.ElementAt(0);
A menudo quiero tomar el primer elemento de un IEnumerable<T>
en .net, y no he encontrado una buena manera de hacerlo. Lo mejor que he encontrado es:
foreach(Elem e in enumerable) {
// do something with e
break;
}
¡Yuck! Entonces, ¿hay una buena manera de hacer esto?
En caso de que esté utilizando .NET 2.0 y no tenga acceso a LINQ:
static T First<T>(IEnumerable<T> items)
{
using(IEnumerator<T> iter = items.GetEnumerator())
{
iter.MoveNext();
return iter.Current;
}
}
Esto debería hacer lo que estás buscando ... usa genéricos para que obtengas el primer elemento de cualquier tipo IEnumerable.
Llámalo así:
List<string> items = new List<string>() { "A", "B", "C", "D", "E" };
string firstItem = First<string>(items);
O
int[] items = new int[] { 1, 2, 3, 4, 5 };
int firstItem = First<int>(items);
Podrías modificarlo lo suficientemente rápido como para imitar el método de extensión IEnumerable.ElementAt () de .NET 3.5:
static T ElementAt<T>(IEnumerable<T> items, int index)
{
using(IEnumerator<T> iter = items.GetEnumerator())
{
for (int i = 0; i <= index; i++, iter.MoveNext()) ;
return iter.Current;
}
}
Llamarlo así:
int[] items = { 1, 2, 3, 4, 5 };
int elemIdx = 3;
int item = ElementAt<int>(items, elemIdx);
Por supuesto, si tiene acceso a LINQ, entonces ya hay muchas buenas respuestas publicadas ...
Si puede usar LINQ, puede usar:
var e = enumerable.First();
Sin embargo, arrojará una excepción si enumerable está vacío: en ese caso puede usar:
var e = enumerable.FirstOrDefault();
FirstOrDefault()
devolverá el default(T)
si el enumerable está vacío, que será null
para los tipos de referencia o el valor cero predeterminado para los tipos de valor.
Si no puede usar LINQ, su enfoque es técnicamente correcto y no es diferente de crear un enumerador utilizando los métodos GetEnumerator
y MoveNext
para recuperar el primer resultado (este ejemplo asume que enumerable es un IEnumerable<Elem>
):
Elem e = myDefault;
using (IEnumerator<Elem> enumer = enumerable.GetEnumerator()) {
if (enumer.MoveNext()) e = enumer.Current;
}
Joel Coehoorn mencionó .Single()
en los comentarios; esto también funcionará, si está esperando que su enumerable contenga exactamente un elemento, sin embargo arrojará una excepción si está vacío o es más grande que un elemento. Existe un método SingleOrDefault()
correspondiente que cubre este escenario de forma similar a FirstOrDefault()
. Sin embargo, David B explica que SingleOrDefault()
aún puede arrojar una excepción en el caso en que el enumerable contenga más de un elemento.
Editar: Gracias Marc Gravell por señalar que tengo que deshacerme de mi objeto IEnumerator
después de usarlo. He editado el ejemplo que no es LINQ para mostrar la palabra clave using
para implementar este patrón.
Si su IEnumerable no expone que es <T>
y Linq falla, puede escribir un método usando la reflexión:
public static T GetEnumeratedItem<T>(Object items, int index) where T : class
{
T item = null;
if (items != null)
{
System.Reflection.MethodInfo mi = items.GetType()
.GetMethod("GetEnumerator");
if (mi != null)
{
object o = mi.Invoke(items, null);
if (o != null)
{
System.Reflection.MethodInfo mn = o.GetType()
.GetMethod("MoveNext");
if (mn != null)
{
object next = mn.Invoke(o, null);
while (next != null && next.ToString() == "True")
{
if (index < 1)
{
System.Reflection.PropertyInfo pi = o
.GetType().GetProperty("Current");
if (pi != null) item = pi
.GetValue(o, null) as T;
break;
}
index--;
}
}
}
}
}
return item;
}
Use FirstOrDefault o un bucle foreach como ya se mencionó. Se debe evitar traer manualmente un enumerador y llamar a Current. foreach dispondrá su enumerador por usted si implementa IDisposable. Cuando llame a MoveNext y Current, debe desecharlo manualmente (si corresponde).
prueba esto
IEnumberable<string> aa;
string a = (from t in aa where t.Equals("") select t.Value).ToArray()[0];
también puedes probar la versión más genérica que te da el elemento ith
enumerable.ElementAtOrDefault (i));
Espero eso ayude
Elem e = enumerable.FirstOrDefault();
//do something with e