2009-01-30 522 views
116

我經常想抓住.net中IEnumerable<T>的第一個元素,但我還沒有找到一個好辦法來做到這一點。最好的我想出來的是:如何從.net的IEnumerable <T>獲取第一個元素?

foreach(Elem e in enumerable) { 
    // do something with e 
    break; 
} 

Yu!那麼,有沒有一個很好的方法來做到這一點?

回答

183

如果你可以使用LINQ可以使用:

var e = enumerable.First(); 

這雖然拋出一個異常,如果枚舉爲空:在這種情況下,你可以使用:

var e = enumerable.FirstOrDefault(); 

FirstOrDefault()將返回default(T)如果枚舉是空的,對於引用類型將爲null,對於值類型則爲默認的「零值」。

如果你不能使用LINQ,那麼你的做法是技術上是正確的,沒有比使用GetEnumeratorMoveNext方法來檢索的第一個結果產生一個枚舉不同(本例假設枚舉是IEnumerable<Elem>):

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

Joel Coehoorn提到.Single()的評論;如果你期望你的枚舉只包含一個元素 - 但是如果它是空的或者大於一個元素,它會拋出一個異常。有一個相應的SingleOrDefault()方法,其覆蓋方式與FirstOrDefault()類似。但是,David B解釋SingleOrDefault()仍然可以在枚舉包含多個項目的情況下引發異常。

編輯:感謝Marc Gravell您指出我需要使用它後處置我IEnumerator對象的 - 我已經編輯了非LINQ示例顯示using關鍵字來實現這種模式。

+1

你應該是`using` enumer - 但除此之外,好;-p – 2009-01-30 22:06:38

+1

感謝馬克 - 編輯。 =) – 2009-01-30 22:35:17

+2

值得指出SingleOrDefault將返回1)唯一的項目,如果只有一個項目。 2)如果沒有項目,則爲null。 3)如果有多個項目,則拋出異常。 – 2011-05-06 02:26:00

6

FirstOrDefault

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

那麼,你沒有指定你正在使用的.Net版本。

假設你有3.5,另一種方法是ElementAt的方法:

var e = enumerable.ElementAt(0); 
31

萬一你使用.NET 2.0和沒有獲得LINQ:

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

這應該做你正在尋找的東西...它使用泛型,所以你得到任何類型的IEnumerable的第一個項目。

調用它像這樣:

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

或者

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

你可以修改它很容易夠到模仿.NET 3.5的IEnumerable的。ElementAt的()擴展方法:

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

調用它像這樣:

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

當然,如果你訪問LINQ,然後有很多很好的答案已經發布...

0

如前所述,使用FirstOrDefault或foreach循環。應避免手動提取枚舉器並調用Current。如果它實現了IDisposable,那麼foreach會爲你配置你的枚舉器。當調用MoveNext和Current時,您必須手動處理它(如果適用)。

0

如果您的IEnumerable的不公開它的<T>和LINQ失敗,你可以寫一個方法使用反射:

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

試試這個

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

,你也可以嘗試更多的通用版本,給你第i個元素

enumerable.ElementAtOrDefault(i));

希望它有助於

相關問題