Respostas:
Se você pode usar o LINQ, pode usar:
var e = enumerable.First();
Isso gerará uma exceção, se enumerable estiver vazio: nesse caso, você poderá usar:
var e = enumerable.FirstOrDefault();
FirstOrDefault()retornará default(T)se o enumerável estiver vazio, que será nullpara tipos de referência ou o 'valor zero' padrão para tipos de valor.
Se você não pode usar o LINQ, sua abordagem é tecnicamente correta e não é diferente de criar um enumerador usando os métodos GetEnumeratore MoveNextpara recuperar o primeiro resultado (este exemplo assume que enumerável é um IEnumerable<Elem>):
Elem e = myDefault;
using (IEnumerator<Elem> enumer = enumerable.GetEnumerator()) {
if (enumer.MoveNext()) e = enumer.Current;
}
Joel Coehoorn mencionado .Single()nos comentários; isso também funcionará, se você espera que o seu enumerável contenha exatamente um elemento - no entanto, lançará uma exceção se estiver vazio ou maior que um elemento. Existe um SingleOrDefault()método correspondente que cobre esse cenário de maneira semelhante a FirstOrDefault(). No entanto, David B explica que SingleOrDefault()ainda pode lançar uma exceção no caso em que o enumerável contém mais de um item.
Edit: Obrigado Marc Gravell por apontar que preciso descartar meu IEnumeratorobjeto depois de usá-lo - editei o exemplo não-LINQ para exibir a usingpalavra-chave para implementar esse padrão.
Caso você esteja usando o .NET 2.0 e não tenha acesso ao LINQ:
static T First<T>(IEnumerable<T> items)
{
using(IEnumerator<T> iter = items.GetEnumerator())
{
iter.MoveNext();
return iter.Current;
}
}
Isso deve fazer o que você está procurando ... ele usa genéricos para obter o primeiro item em qualquer tipo IEnumerable.
Chame assim:
List<string> items = new List<string>() { "A", "B", "C", "D", "E" };
string firstItem = First<string>(items);
Ou
int[] items = new int[] { 1, 2, 3, 4, 5 };
int firstItem = First<int>(items);
Você pode modificá-lo com prontidão suficiente para imitar o método de extensão IEnumerable.ElementAt () do .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;
}
}
Chamando assim:
int[] items = { 1, 2, 3, 4, 5 };
int elemIdx = 3;
int item = ElementAt<int>(items, elemIdx);
Claro, se você fazer têm acesso a LINQ, então há uma abundância de boas respostas já postou ...
Bem, você não especificou qual versão do .Net você está usando.
Supondo que você tenha 3,5, outra maneira é o método ElementAt:
var e = enumerable.ElementAt(0);
Elem e = enumerable.FirstOrDefault();
//do something with e
Use FirstOrDefault ou um loop foreach como já mencionado. Buscar manualmente um enumerador e chamar Current deve ser evitado. O foreach descartará seu enumerador para você se implementar IDisposable. Ao chamar MoveNext e Current, você deve descartá-lo manualmente (se aplicável).
Se seu IEnumerable não o <T>expuser e o Linq falhar, você poderá escrever um método usando a reflexão:
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;
}
você também pode tentar a versão mais genérica que fornece o i-ésimo elemento
enumerable.ElementAtOrDefault (i));
espero que ajude