Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.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
.net IEnumerable<;T>;代表;“休息”;一个IEnumerable<;T>;序列_.net_Linked List_Ienumerable_Ienumerator - Fatal编程技术网

.net IEnumerable<;T>;代表;“休息”;一个IEnumerable<;T>;序列

.net IEnumerable<;T>;代表;“休息”;一个IEnumerable<;T>;序列,.net,linked-list,ienumerable,ienumerator,.net,Linked List,Ienumerable,Ienumerator,如果我正在浏览一个IEnumerable,是否有办法获得一个新的IEnumerable,表示当前项之后的剩余项 例如,我想编写一个扩展方法IEnumerator.Remaining(): IEnumerable序列=。。。 IEnumerator枚举器=序列。GetEnumerator(); if(enumerator.MoveNext()&&enumerator.MoveNext()){ IEnumerable rest=枚举数.Remaining(); //“rest”将包含从第3个元素开始

如果我正在浏览一个
IEnumerable
,是否有办法获得一个新的
IEnumerable
,表示当前项之后的剩余项

例如,我想编写一个扩展方法
IEnumerator.Remaining()

IEnumerable序列=。。。
IEnumerator枚举器=序列。GetEnumerator();
if(enumerator.MoveNext()&&enumerator.MoveNext()){
IEnumerable rest=枚举数.Remaining();
//“rest”将包含从第3个元素开始的“sequence”元素
}
我在考虑一种单链表的集合,所以应该有一种方法来表示任何剩余的元素,对吗?我在
IEnumerable
IEnumerator
上都没有看到任何方法可以做到这一点,因此它可能与潜在的无限、不确定的元素序列的概念不兼容。

这是您想要使用的两种方法:

IEnumerable<int> sequence = ...
IEnumerable<int> pair = sequence.Take(2); //First two elements
IEnumerable<int> remaining = sequence.Skip(2);
IEnumerable序列=。。。
IEnumerable pair=sequence.Take(2)//前两个要素
IEnumerable剩余=序列。跳过(2);

如果必须使用
IEnumerator
而不是
IEnumerable
(所有好的扩展方法都有),那么这里有两个简单的方法

此线程只能枚举一次(并绑定到原始可枚举项,这意味着如果另一个线程更改源列表,则可能会出现异常):

公共静态IEnumerable剩余值(此IEnumerator值){
while(value.MoveNext()){
收益率返回值。当前值;
}
}
这一个构建了一个列表,可以重复枚举(并且与原始枚举器断开连接,因此您不必担心源IEnumerable的更改):

公共静态IEnumerable剩余值(此IEnumerator值){
列表=新列表();
while(value.MoveNext())list.Add(value.Current);
退货清单;
}

如果你想得到一个
IEnumerator
并得到一个
IEnumerable
表示序列的其余部分,从字面上看,你需要做一些魔术才能达到目的

其原因是,在一般意义上,一个可枚举项可以被多次枚举,而一个枚举器不能,它本身只是其中的一个“多次”

首先,您可以尝试找出正在处理的集合类型,从而在原始枚举数的其余部分的基础上返回一个适当的枚举数。你要去的原因

或者。。。您可以将枚举数的其余部分缓存到新集合中并返回该集合。这当然会消耗您的原始枚举数,不管它是什么,而且在时间或内存方面可能会很昂贵

或者。。。您可以执行一些人建议的操作,实际上不返回枚举数,而是使用enumerable类的Skip和Take方法返回所需的内容。这将返回一个新的可枚举项,每次对其进行枚举时,它都会对原始可枚举项进行枚举,跳过前两项,并生成其余项

让我改写最后一段。如果不尝试将
IEnumerator
的其余部分作为新的可枚举项返回,而只是处理原始集合,那么处理起来就容易多了

下面是一些缓存元素的代码。这样做的好处是,如果从生成的枚举中生成2个或多个枚举数(甚至仅1个),然后让该枚举超出范围,则当枚举数开始在元素中移动时,垃圾收集器将开始收集经过的元素

换句话说,如果您这样做:

var enumerable = enumerator.Remaining();
var enumerator1 = enumerable.GetEnumerator();
var enumerator2 = enumerable.GetEnumerator();

enumerator1.MoveNext();
enumerator2.MoveNext();
<-- at this point, enumerable is no longer used, and the first (head) element
    of the enumerable is no longer needed (there's no way to get to it)
    it can be garbage collected.

如果您的目标是能够在
IEnumerator
上直接使用
foreach
,我建议如下:

public struct WrappedEnumerator<T>
{
    T myEnumerator;
    public T GetEnumerator() { return myEnumerator; }
    public WrappedEnumerator(T theEnumerator) { myEnumerator = theEnumerator; }
}
public static class AsForEachHelper
{
    static public WrappedEnumerator<IEnumerator<T>> AsForEach<T>(this IEnumerator<T> theEnumerator)
        { return new WrappedEnumerator<IEnumerator<T>>(theEnumerator);}

    static public WrappedEnumerator<System.Collections.IEnumerator> AsForEach(this System.Collections.IEnumerator theEnumerator) 
        { return new WrappedEnumerator<System.Collections.IEnumerator>(theEnumerator); }

    [Obsolete("Structs implementing IEnumerator<T> should be boxed before use", false)]
    static public WrappedEnumerator<System.Collections.IEnumerator> AsForEach<T>(this T theEnumerator) where T : struct, System.Collections.IEnumerator 
    { return new WrappedEnumerator<System.Collections.IEnumerator>(theEnumerator) ; }
}
public结构包装器
{
髓鞘分子;
public T GetEnumerator(){return myEnumerator;}
公共WrappedEnumerator(T theEnumerator){myEnumerator=theEnumerator;}
}
作为ForEachHelper的公共静态类
{
静态公共包装计数器AsForEach(此IEnumerator为分子)
{返回新的WrappedEnumerator(theEnumerator);}
静态公共WrappedEnumerator AsForEach(此System.Collections.IEnumerator为分子)
{返回新的WrappedEnumerator(theEnumerator);}
[过时(“实现IEnumerator的结构应在使用前装箱”,false)]
静态公共WrappedEnumerator作为foreach(此T theEnumerator),其中T:struct,System.Collections.IEnumerator
{返回新的WrappedEnumerator(theEnumerator);}
}

如果
foo
是一个类型为
IEnumerator
IEnumerator
的变量,或者是从其中派生的任何类类型的变量,那么可以简单地说
foreach(foo.AsForEach()中的任何内容)
;如果循环提前退出,任何未读取的项都将保留在枚举器中。但是请注意,像
myEnumerator Foo=someList.GetEnumerator()
这样的语句,其中
someList
List
myEnumerator
定义为结构类型,这与
WrappedEnumerator
方法不兼容。如果你真的很勇敢,你可以删除
过时的
标记(或将其参数更改为
false
),以允许对非固定枚举数使用
AsForEach
,但你应该注意,在结构类型枚举数上调用
AsForEach
,可能会获取枚举状态的快照,枚举快照可能不会影响原始快照的状态。

很遗憾,IEnumerable上没有克隆方法。这可能会对你有所帮助。您可以实现一个EnumerableEx类,该类封装IEnumerable并支持克隆。
rest=sequence.Skip(2)
会复制您的示例,但不会泛化…我知道这些方法,但不会
public static IEnumerable<T> Remaining<T>( this IEnumerator<T> value ) {
    List<T> list = new List<T>();
    while( value.MoveNext() ) list.Add( value.Current );

    return list;
}
var enumerable = enumerator.Remaining();
var enumerator1 = enumerable.GetEnumerator();
var enumerator2 = enumerable.GetEnumerator();

enumerator1.MoveNext();
enumerator2.MoveNext();
<-- at this point, enumerable is no longer used, and the first (head) element
    of the enumerable is no longer needed (there's no way to get to it)
    it can be garbage collected.
using System;
using System.Collections.Generic;
using System.Collections;

namespace SO2829956
{
    public class EnumeratorEnumerable<T> : IEnumerable<T>
    {
        private class Node
        {
            public T Value;
            public Node Next;
        }

        private class Enumerator : IEnumerator<T>
        {
            private IEnumerator<T> _Enumerator;
            private Node _Current;

            public Enumerator(IEnumerator<T> enumerator, Node headElement)
            {
                _Enumerator = enumerator;
                _Current = headElement;
            }

            public T Current
            {
                get { return _Current.Value; }
            }

            public void Dispose()
            {
                _Enumerator.Dispose();
            }

            object IEnumerator.Current
            {
                get { return Current; }
            }

            public bool MoveNext()
            {
                if (_Current.Next != null)
                {
                    _Current = _Current.Next;
                    return true;
                }
                else if (_Enumerator.MoveNext())
                {
                    _Current.Next = new Node
                    {
                        Value = _Enumerator.Current
                    };
                    _Current = _Current.Next;
                    return true;
                }
                else
                {
                    _Enumerator.Dispose();
                    return false;
                }
            }

            public void Reset()
            {
                throw new NotImplementedException();
            }
        }

        private IEnumerator<T> _Enumerator;
        private Node _FirstElement;

        public EnumeratorEnumerable(IEnumerator<T> enumerator)
        {
            _Enumerator = enumerator;
            _FirstElement = new Node
            {
                Next = null,
                Value = enumerator.Current
            };
        }

        public IEnumerator<T> GetEnumerator()
        {
            return new Enumerator(_Enumerator, _FirstElement);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    public static class EnumeratorExtensions
    {
        public static IEnumerable<T> Remaining<T>(
            this IEnumerator<T> enumerator)
        {
            return new EnumeratorEnumerable<T>(enumerator);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<int> values = new List<int> { 1, 2, 3, 4, 5 };
            IEnumerator<int> enumerator = values.GetEnumerator();
            enumerator.MoveNext();
            enumerator.MoveNext();

            var enumerable = enumerator.Remaining();
            foreach (var i in enumerable)
                Console.Out.WriteLine(i);
            foreach (var i in enumerable)
                Console.Out.WriteLine(i);
        }
    }
}
3
4
5
3
4
5
public struct WrappedEnumerator<T>
{
    T myEnumerator;
    public T GetEnumerator() { return myEnumerator; }
    public WrappedEnumerator(T theEnumerator) { myEnumerator = theEnumerator; }
}
public static class AsForEachHelper
{
    static public WrappedEnumerator<IEnumerator<T>> AsForEach<T>(this IEnumerator<T> theEnumerator)
        { return new WrappedEnumerator<IEnumerator<T>>(theEnumerator);}

    static public WrappedEnumerator<System.Collections.IEnumerator> AsForEach(this System.Collections.IEnumerator theEnumerator) 
        { return new WrappedEnumerator<System.Collections.IEnumerator>(theEnumerator); }

    [Obsolete("Structs implementing IEnumerator<T> should be boxed before use", false)]
    static public WrappedEnumerator<System.Collections.IEnumerator> AsForEach<T>(this T theEnumerator) where T : struct, System.Collections.IEnumerator 
    { return new WrappedEnumerator<System.Collections.IEnumerator>(theEnumerator) ; }
}