繁体   English   中英

如何从.net中的IEnumerable <T>获取第一个元素?

[英]How do I get the first element from an IEnumerable<T> in .net?

我经常想在.net中获取IEnumerable<T>的第一个元素,我还没有找到一个很好的方法来做到这一点。 我提出的最好的是:

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

呸! 那么,有一个很好的方法来做到这一点?

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

var e = enumerable.First();

如果enumerable为空,这将抛出异常:在这种情况下,您可以使用:

var e = enumerable.FirstOrDefault();

如果枚举为空,则FirstOrDefault()将返回default(T) ,对于引用类型,它将为null ,对于值类型,默认为“零值”。

如果你不能使用LINQ,那么你的方法在技术上是正确的,与使用GetEnumeratorMoveNext方法创建枚举器来检索第一个结果没有区别(这个例子假设enumerable是一个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关键字来实现此模式。

以防您使用.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,然后有很多已经贴好答案...

好吧,您没有指定您正在使用的.Net版本。

假设你有3.5,另一种方法是ElementAt方法:

var e = enumerable.ElementAt(0);

FirstOrDefault

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

如果您的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;
}

试试这个

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

您还可以尝试更通用的版本,它会为您提供第i个元素

enumerable.ElementAtOrDefault(I));

希望能帮助到你

如前所述,使用FirstOrDefault或foreach循环。 应该避免手动获取枚举器并调用Current。 如果它实现IDisposable,foreach将为您处置您的枚举器。 调用MoveNext和Current时,必须手动处理它(如果适用)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM