Risposte:
Se puoi usare LINQ puoi usare:
var e = enumerable.First();
Ciò genererà un'eccezione se enumerable è vuoto: nel qual caso è possibile utilizzare:
var e = enumerable.FirstOrDefault();
FirstOrDefault()restituirà default(T)se l'enumerabile è vuoto, che sarà nullper i tipi di riferimento o il "valore zero" predefinito per i tipi di valore.
Se non puoi usare LINQ, il tuo approccio è tecnicamente corretto e non è diverso dalla creazione di un enumeratore usando i metodi GetEnumeratore MoveNextper recuperare il primo risultato (questo esempio presuppone che enumerable sia un IEnumerable<Elem>):
Elem e = myDefault;
using (IEnumerator<Elem> enumer = enumerable.GetEnumerator()) {
if (enumer.MoveNext()) e = enumer.Current;
}
Joel Coehoorn menzionato .Single()nei commenti; questo funzionerà anche se ti aspetti che il tuo enumerabile contenga esattamente un elemento, tuttavia genererà un'eccezione se è vuoto o più grande di un elemento. Esiste un SingleOrDefault()metodo corrispondente che copre questo scenario in modo simile a FirstOrDefault(). Tuttavia, David B spiega che SingleOrDefault()potrebbe ancora generare un'eccezione nel caso in cui l'enumerabile contenga più di un elemento.
Modifica: Grazie a Marc Gravell per aver sottolineato che devo smaltire il mio IEnumeratoroggetto dopo averlo usato - ho modificato l'esempio non LINQ per visualizzare la usingparola chiave per implementare questo modello.
Nel caso in cui si utilizzi .NET 2.0 e non si abbia accesso a LINQ:
static T First<T>(IEnumerable<T> items)
{
using(IEnumerator<T> iter = items.GetEnumerator())
{
iter.MoveNext();
return iter.Current;
}
}
Questo dovrebbe fare quello che stai cercando ... usa generici in modo da ottenere il primo elemento su qualsiasi tipo IEnumerable.
Chiamalo così:
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);
È possibile modificarlo abbastanza rapidamente da imitare il metodo di estensione IEnumerable.ElementAt () di .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;
}
}
Chiamandolo così:
int[] items = { 1, 2, 3, 4, 5 };
int elemIdx = 3;
int item = ElementAt<int>(items, elemIdx);
Naturalmente se si fare avere accesso a LINQ, poi ci sono un sacco di buone risposte postato già ...
Bene, non hai specificato quale versione di .Net stai usando.
Supponendo di avere 3.5, un altro modo è il metodo ElementAt:
var e = enumerable.ElementAt(0);
Elem e = enumerable.FirstOrDefault();
//do something with e
Utilizzare FirstOrDefault o un ciclo foreach come già menzionato. È necessario evitare di recuperare manualmente un enumeratore e chiamare Current. foreach eliminerà il tuo enumeratore per te se implementa IDisposable. Quando si chiama MoveNext e Current, è necessario eliminarlo manualmente (se applicabile).
Se il tuo IEnumerable non lo <T>rivela e Linq fallisce, puoi scrivere un metodo usando reflection:
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;
}
puoi anche provare la versione più generica che ti dà l'elemento ith
enumerable.ElementAtOrDefault (i));
spero che sia d'aiuto