Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# linq Last()如何确定最后一项?_C#_.net_Linq - Fatal编程技术网

C# linq Last()如何确定最后一项?

C# linq Last()如何确定最后一项?,c#,.net,linq,C#,.net,Linq,我不明白Current怎么可以为null,LINQ函数Last()怎么可以返回一个对象。我认为Last使用GetEnumerator并一直运行,直到current==null并返回对象。但是,正如您所看到的,第一个GetEnumerator().Current为null,最后一个以某种方式返回一个对象 linq Last()是如何工作的 Last()。空值通常不用作序列中的终止符 因此,实现可能如下所示: public static T Last<T>(this IEnumerabl

我不明白Current怎么可以为null,LINQ函数Last()怎么可以返回一个对象。我认为Last使用GetEnumerator并一直运行,直到current==null并返回对象。但是,正如您所看到的,第一个GetEnumerator().Current为null,最后一个以某种方式返回一个对象

linq Last()是如何工作的

Last()。空值通常不用作序列中的终止符

因此,实现可能如下所示:

public static T Last<T>(this IEnumerable<T> source)
{
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }
    using (IEnumerator<T> iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            throw new InvalidOperationException("Empty sequence");
        }
        T value = iterator.Current;
        while (iterator.MoveNext())
        {
            value = iterator.Current;
        }
        return value;
    }
}
public static T Last(此IEnumerable源代码)
{
if(source==null)
{
抛出新的ArgumentNullException(“源”);
}
使用(IEnumerator迭代器=source.GetEnumerator())
{
如果(!iterator.MoveNext())
{
抛出新的InvalidOperationException(“空序列”);
}
T值=迭代器当前值;
while(iterator.MoveNext())
{
value=iterator.Current;
}
返回值;
}
}
(这可以通过一个
foreach
循环来实现,但上面更明确地显示了交互。这也忽略了直接访问最后一个元素的可能性。)

系统.Core.dll上使用:

public static TSource Last<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    IList<TSource> list = source as IList<TSource>;
    if (list != null)
    {
        int count = list.Count;
        if (count > 0)
        {
            return list[count - 1];
        }
    }
    else
    {
        using (IEnumerator<TSource> enumerator = source.GetEnumerator())
        {
            if (enumerator.MoveNext())
            {
                TSource current;
                do
                {
                    current = enumerator.Current;
                }
                while (enumerator.MoveNext());
                return current;
            }
        }
    }
    throw Error.NoElements();
}
publicstatictsource Last(此IEnumerable源)
{
if(source==null)
{
抛出错误。ArgumentNull(“源”);
}
IList list=源作为IList;
如果(列表!=null)
{
int count=list.count;
如果(计数>0)
{
返回列表[计数-1];
}
}
其他的
{
使用(IEnumerator enumerator=source.GetEnumerator())
{
if(枚举数.MoveNext())
{
t电源电流;
做
{
当前=枚举数。当前;
}
while(枚举数.MoveNext());
回流;
}
}
}
抛出错误。NoElements();
}

对于数组,在任何MoveNext()之前的枚举数的第一个值是索引-1处的项。
您必须执行一次“移动下一步”才能输入实际的集合。
这样做是为了使枚举器的构造函数不做太多工作,并使这些构造有效:


请记住,每次调用
GetEnumerator
通常不一定返回相同的
Enumerator
。另外,由于
thing.GetEnumerator()
返回一个新的
Enumerator
,它将以未初始化的方式启动(您还没有调用
MoveNext()
),因此
thing.GetEnumerator()。根据定义,当前的
将始终为空

(我想…

如果您查看备注部分,他们会说明以下内容:

最初,枚举数位于集合中第一个元素的前面在此位置,当前未定义。因此,在读取当前值之前,必须调用MoveNext将枚举数前进到集合的第一个元素


因此,您必须调用
MoveNext()
一次才能获取第一项。否则您将一无所获。

另外,不会
collection.GetEnumerator().Current
返回“集合第一个元素之前的对象”?在Current有一个定义的值之前,您不需要至少调用一次MoveNext吗?Lasse:是的,尽管C生成的迭代器块忽略了这一点:(
MoveNext()在
if
块中,在
Current
之前调用
。结果未定义,通常为null,但仍然未定义。您将序列与其枚举数混淆。想象一本书有编号的页面。这是一个序列。想象一个书签,标记一个特定页面。这是一个枚举数。您可以有一百个如果需要,可以在书中添加书签,所有书签都会标记不同的位置。调用GetEnumerator。Current会在您还没有将书签放入书中时询问书签所在的页面;不要这样做。这解释了我的思维过程有什么问题。谢谢!
public static TSource Last<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    IList<TSource> list = source as IList<TSource>;
    if (list != null)
    {
        int count = list.Count;
        if (count > 0)
        {
            return list[count - 1];
        }
    }
    else
    {
        using (IEnumerator<TSource> enumerator = source.GetEnumerator())
        {
            if (enumerator.MoveNext())
            {
                TSource current;
                do
                {
                    current = enumerator.Current;
                }
                while (enumerator.MoveNext());
                return current;
            }
        }
    }
    throw Error.NoElements();
}
while (enumerator.MoveNext()) {
      // Do Stuff
 }

if(enumerator.MoveNext()) {
      // Do Stuff
 } // This is identical to Linq's .Any(), essentially.