【发布时间】:2009-01-30 21:12:21
【问题描述】:
我经常想在 .net 中获取 IEnumerable<T> 的第一个元素,但我还没有找到一个好的方法。我想出的最好的是:
foreach(Elem e in enumerable) {
// do something with e
break;
}
呸!那么,有什么好的方法可以做到这一点吗?
【问题讨论】:
我经常想在 .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,那么您的方法在技术上是正确的,并且与使用 GetEnumerator 和 MoveNext 方法创建枚举器来检索第一个结果没有什么不同(此示例假定 enumerable 是 IEnumerable<Elem>) :
Elem e = myDefault;
using (IEnumerator<Elem> enumer = enumerable.GetEnumerator()) {
if (enumer.MoveNext()) e = enumer.Current;
}
Joel Coehoorn 在 cmets 中提到了.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);
【讨论】:
Elem e = enumerable.FirstOrDefault();
//do something with e
【讨论】:
试试这个
IEnumberable<string> aa;
string a = (from t in aa where t.Equals("") select t.Value).ToArray()[0];
【讨论】:
如前所述,使用 FirstOrDefault 或 foreach 循环。应避免手动获取枚举器并调用 Current。如果 foreach 实现 IDisposable,它将为您处理您的枚举器。调用 MoveNext 和 Current 时,您必须手动处理它(如果适用)。
【讨论】:
如果您的 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;
}
【讨论】:
您也可以尝试更通用的版本,它为您提供第 i 个元素
enumerable.ElementAtOrDefault(i));
希望对你有帮助
【讨论】: