Проблема с результатом Linq - PullRequest
0 голосов
/ 27 мая 2011

Привет! У меня возникла проблема с каким-то методом, который должен выполнить действие с некоторым экземпляром объекта IEnumerator, пример кода показывает случай:

class Program
    {        
        static void Main(string[] args)
        {
            string[] testArray = { "Item1", "Item2" };

            var query = testArray.Select((item, index) => new { index, item });

            Console.WriteLine("Query run 1, {0}", Environment.NewLine);

            foreach (var obj in query)
            {
                Console.WriteLine("{0}", obj);
            }

            Console.WriteLine("Query run 2, {0}", Environment.NewLine);

            doAction<object>(query as IEnumerator<object>, obj => Console.WriteLine(obj) );


            Console.WriteLine("Query run 3 ( same as run 1), {0}", Environment.NewLine);

            foreach (var obj in query)
            {
                Console.WriteLine("{0}", obj);
            }

            Object tmp = Console.ReadLine();
        }


        private static void doAction<T>(IEnumerator<T> enumerator, Action<T> action)
        {

            if (enumerator == null)
            {
                throw new ArgumentNullException("enumerator");
            }

            if (action == null)
            {
                throw new ArgumentNullException("action");
            }


            while (enumerator.MoveNext())
            {
                action(enumerator.Current);
            }

        }
    }

Вывод:

Query run 1,

{ index = 0, item = Item1 }
{ index = 1, item = Item2 }
Query run2,

Query run 3 ( same as run 1), 

{ index = 0, item = Item1 }
{ index = 1, item = Item2 }

Кто-нибудь знает, каким методом doAction не действуют?

Реальная проблема в том, что мне нужен ответ на английском языке, потому что мой действительно плохой, и я не могу объяснить, почему это происходит с моим другом.

Заранее спасибо.

Thnaks.

1 Ответ

3 голосов
/ 27 мая 2011

Да - вы не должны использовать IEnumerator<T> напрямую, только IEnumerable<T>. По сути, вы видите странность того, как компилятор C # реализует блоки итераторов: есть один тип, который реализует как IEnumerable<T> , так и IEnumerator<T>. Это само по себе необычно, но сделано из соображений производительности. Это не то, чем вы должны воспользоваться или положиться.

По сути, приведение IEnumerable<T> к IEnumerator<T> - плохая идея - вы не должны делать это. Это разные интерфейсы, представляющие слегка разные идеи - различие между «последовательностью, по которой может быть повторен» и «чем-то, что является итерацией по последовательности».

Если вы действительно хотите использовать IEnumerator<T> в качестве типа параметра для doAction (который обычно будет DoAction, кстати), просто вызовите GetEnumerator() вместо:

using (var iterator = query.GetEnumerator())
{
    doAction<object>(iterator, obj => Console.WriteLine(obj) );
}
...