我经常想抓住.net中IEnumerable<T>
的第一个元素,但我还没有找到一个好办法来做到这一点。最好的我想出来的是:如何从.net的IEnumerable <T>获取第一个元素?
foreach(Elem e in enumerable) {
// do something with e
break;
}
Yu!那么,有没有一个很好的方法来做到这一点?
我经常想抓住.net中IEnumerable<T>
的第一个元素,但我还没有找到一个好办法来做到这一点。最好的我想出来的是:如何从.net的IEnumerable <T>获取第一个元素?
foreach(Elem e in enumerable) {
// do something with e
break;
}
Yu!那么,有没有一个很好的方法来做到这一点?
如果你可以使用LINQ可以使用:
var e = enumerable.First();
这虽然抛出一个异常,如果枚举为空:在这种情况下,你可以使用:
var e = enumerable.FirstOrDefault();
FirstOrDefault()
将返回default(T)
如果枚举是空的,对于引用类型将为null
,对于值类型则为默认的“零值”。
如果你不能使用LINQ,那么你的做法是技术上是正确的,没有比使用GetEnumerator
和MoveNext
方法来检索的第一个结果产生一个枚举不同(本例假设枚举是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
关键字来实现这种模式。
Elem e = enumerable.FirstOrDefault();
//do something with e
那么,你没有指定你正在使用的.Net版本。
假设你有3.5,另一种方法是ElementAt的方法:
var e = enumerable.ElementAt(0);
万一你使用.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,然后有很多很好的答案已经发布...
如前所述,使用FirstOrDefault或foreach循环。应避免手动提取枚举器并调用Current。如果它实现了IDisposable,那么foreach会为你配置你的枚举器。当调用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;
}
试试这个
IEnumberable<string> aa;
string a = (from t in aa where t.Equals("") select t.Value).ToArray()[0];
,你也可以尝试更多的通用版本,给你第i个元素
enumerable.ElementAtOrDefault(i));
希望它有助于
你应该是`using` enumer - 但除此之外,好;-p – 2009-01-30 22:06:38
感谢马克 - 编辑。 =) – 2009-01-30 22:35:17
值得指出SingleOrDefault将返回1)唯一的项目,如果只有一个项目。 2)如果没有项目,则为null。 3)如果有多个项目,则抛出异常。 – 2011-05-06 02:26:00