2009-01-30 3 views

Antwort

183

Wenn Sie LINQ verwenden, können Sie verwenden:

var e = enumerable.First(); 

Dies wird eine Ausnahme allerdings aus, wenn zählbare leer ist: in diesem Fall können Sie verwenden:

var e = enumerable.FirstOrDefault(); 

FirstOrDefault() kehrt default(T) wenn Der Aufzählungswert ist leer. Er lautet null für Referenztypen oder den Standardwert 'Nullwert' für Werttypen.

Wenn Sie nicht LINQ verwenden, dann ist Ihr Ansatz ist technisch korrekt und nicht anders als einen Enumerator Schaffung der GetEnumerator und MoveNext Methoden unter Verwendung des ersten Ergebnisses abzurufen (in diesem Beispiel wird davon ausgegangen enumerable ist ein IEnumerable<Elem>):

Elem e = myDefault; 
using (IEnumerator<Elem> enumer = enumerable.GetEnumerator()) { 
    if (enumer.MoveNext()) e = enumer.Current; 
} 

Joel Coehoorn erwähnt .Single() in den Kommentaren; Dies funktioniert auch, wenn Sie erwarten, dass Ihr Enumerable genau ein Element enthält. Es wird jedoch eine Ausnahme ausgelöst, wenn es entweder leer oder größer als ein Element ist. Es gibt eine entsprechende SingleOrDefault() Methode, die dieses Szenario in ähnlicher Weise zu FirstOrDefault() abdeckt. David B erklärt jedoch, dass SingleOrDefault() noch eine Ausnahme auslösen kann, wenn das Enumerable mehr als ein Element enthält.

Edit: Danke Marc Gravell für den Hinweis auf, dass ich von meinem IEnumerator Objekt zu entsorgen, nachdem es mit - ich habe das nicht-LINQ Beispiel bearbeiten das using Schlüsselwort angezeigt werden, dieses Muster zu implementieren.

+1

Sie sollten 'using' enumer - aber anders als die, gute ;-p –

+1

Dank Marc - bearbeitet. =) –

+2

Es lohnt sich darauf hinzuweisen, dass SingleOrDefault zurückkommt. 1) Das einzige Element, wenn nur ein Element vorhanden ist. 2) null, wenn keine Gegenstände vorhanden sind. 3) Wirf eine Ausnahme, wenn es mehr als einen Gegenstand gibt. –

6

FirstOrDefault?

Elem e = enumerable.FirstOrDefault(); 
//do something with e 
16

Nun, Sie haben nicht angegeben, welche Version von .Net Sie verwenden.

Angenommen, Sie haben 3.5, eine andere Art und Weise ist die ElementAt Methode:

var e = enumerable.ElementAt(0); 
+1

ElementAt (0), schön und einfach. – JMD

31

Gerade falls Sie verwenden .NET 2.0 und haben keinen Zugriff auf LINQ:

static T First<T>(IEnumerable<T> items) 
{ 
    using(IEnumerator<T> iter = items.GetEnumerator()) 
    { 
     iter.MoveNext(); 
     return iter.Current; 
    } 
} 

Diese sollte tun, was Sie suchen ... es verwendet Generika, damit Sie das erste Element auf einem beliebigen Typ IEnumerable erhalten.

Nennen Sie es, wie so:

List<string> items = new List<string>() { "A", "B", "C", "D", "E" }; 
string firstItem = First<string>(items); 

Oder

int[] items = new int[] { 1, 2, 3, 4, 5 }; 
int firstItem = First<int>(items); 

Sie könnten ändern es leicht genug, um .NET 3.5 ist IEnumerable zu imitieren.ElementAt() Erweiterungsmethode:

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; 
    } 
} 

es wie so aufrufen:

int[] items = { 1, 2, 3, 4, 5 }; 
int elemIdx = 3; 
int item = ElementAt<int>(items, elemIdx); 

Natürlich, wenn Sie zu tun haben Zugriff auf LINQ, dann gibt es viele gute Antworten bereits gebucht ...

+0

Sie sollten 'using' iter sein –

+0

Hoppla, natürlich haben Sie Recht, danke. Ich habe meine Beispiele korrigiert. – BenAlabaster

+0

Iteratoren sind Einwegartikel? Wusste nicht, dass ... –

0

Verwenden Sie FirstOrDefault oder eine foreach-Schleife wie bereits erwähnt. Das manuelle Abrufen eines Enumerators und das Aufrufen von Current sollten vermieden werden. foreach wird Ihren Enumerator für Sie bereitstellen, wenn IDisposable implementiert wird. Wenn Sie MoveNext und Current aufrufen, müssen Sie sie manuell entsorgen (falls anwendbar).

+1

Welchen Beweis gibt es, dass der Enumerator vermieden werden sollte? Leistungstests an meinem Gerät zeigen, dass es einen Leistungszuwachs von ca. 10% gegenüber dem foreach hat. – BenAlabaster

+0

Es hängt davon ab, was Sie aufzählen. Ein Erumerator könnte die Verbindung zur Datenbank schließen, den Dateizugriffspunkt schließen und schließen, einige gesperrte Objekte freigeben, usw. Einen Enumerator einer Integer-Liste nicht zu entfernen, wird nicht schaden, nehme ich an. – Mouk

0

Wenn Ihr IEnumerable nicht aussetzen wird es <T> und Linq fehlschlägt, eine Methode unter Verwendung von Reflexion schreiben:

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; 
} 
0

versuchen diese

IEnumberable<string> aa; 
string a = (from t in aa where t.Equals("") select t.Value).ToArray()[0]; 
0

Sie auch die generische Version können versuchen, die gibt Ihnen das i-te Element

enumerable.ElementAtOrDefault (i));

hoffen, es hilft

Verwandte Themen