C #: Как перевести ключевое слово Yield - PullRequest
4 голосов
/ 13 января 2011
  1. Как будет выглядеть пример MSDN без ключевого слова yield ?Вы можете использовать любой пример, если вы предпочитаете.Я просто хотел бы понять, что происходит под капотом.
  2. Оператор yield охотно или лениво оценивается?

Пример:

using System;
using System.Collections;
public class List
{
    public static IEnumerable Power(int number, int exponent)
    {
        int counter = 0;
        int result = 1;
        while (counter++ < exponent)
        {
            result = result * number;
            yield return result;
        }
    }

    static void Main()
    {
        // Display powers of 2 up to the exponent 8:
        foreach (int i in Power(2, 8))
        {
            Console.Write("{0} ", i);
        }
    }
}

Оператор yield оценивается с нетерпением, вот мое предположение:

    public static IEnumerable Power(int number, int exponent)
    {
        int counter = 0;
        int result = 1;
        List<int> powers;
        while (counter++ < exponent)
        {
            result = result * number;
            powers.add(result);
        }
        return powers;
    }

Понятия не имею, на что это могло бы быть похоже, если вычислить оператор yield на *.Отражатель дает это:

public class List
{
    // Methods
    public List();
    private static void Main();
    public static IEnumerable Power(int number, int exponent);

    // Nested Types
    [CompilerGenerated]
    private sealed class <Power>d__0 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
    {
        // Fields
        private int <>1__state;
        private object <>2__current;
        public int <>3__exponent;
        public int <>3__number;
        private int <>l__initialThreadId;
        public int <counter>5__1;
        public int <result>5__2;
        public int exponent;
        public int number;

        // Methods
        [DebuggerHidden]
        public <Power>d__0(int <>1__state);
        private bool MoveNext();
        [DebuggerHidden]
        IEnumerator<object> IEnumerable<object>.GetEnumerator();
        [DebuggerHidden]
        IEnumerator IEnumerable.GetEnumerator();
        [DebuggerHidden]
        void IEnumerator.Reset();
        void IDisposable.Dispose();

        // Properties
        object IEnumerator<object>.Current { [DebuggerHidden] get; }
        object IEnumerator.Current { [DebuggerHidden] get; }
    }
}

IEnumerator<object> IEnumerable<object>.GetEnumerator()
{
    List.<Power>d__0 d__;
    if ((Thread.CurrentThread.ManagedThreadId == this.<>l__initialThreadId) && (this.<>1__state == -2))
    {
        this.<>1__state = 0;
        d__ = this;
    }
    else
    {
        d__ = new List.<Power>d__0(0);
    }
    d__.number = this.<>3__number;
    d__.exponent = this.<>3__exponent;
    return d__;
}



private bool MoveNext()
{
    switch (this.<>1__state)
    {
        case 0:
            this.<>1__state = -1;
            this.<counter>5__1 = 0;
            this.<result>5__2 = 1;
            while (this.<counter>5__1++ < this.exponent)
            {
                this.<result>5__2 *= this.number;
                this.<>2__current = this.<result>5__2;
                this.<>1__state = 1;
                return true;
            Label_0065:
                this.<>1__state = -1;
            }
            break;

        case 1:
            goto Label_0065;
    }
    return false;
}

Ответы [ 4 ]

11 голосов
/ 13 января 2011

Во-первых, доходность не является оператором . доходность и разрыв доходности составляют заявления .

Существует множество статей о том, как компилятор реализует блоки итераторов. Начните с чтения секции спецификации C # для блоков итераторов; он дает несколько советов о том, как разработчик C # может захотеть сделать это.

Далее читайте серию Раймонда Чена «Реализация итераторов в C # и ее последствия»

http://www.bing.com/search?q=raymond+chen+the+implementation+of+iterators

Далее прочитайте главу книги Джона Скита на эту тему:

http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx

Если после всего этого вы по-прежнему заинтересованы, прочитайте мою серию о факторах дизайна, которые вошли в эту функцию:

http://blogs.msdn.com/b/ericlippert/archive/tags/iterators/

7 голосов
/ 13 января 2011

В старые добрые времена, до того, как у нас появился оператор yield, мы писали классы, в которых реализован IEnumerator.

class PowerEnumerator : IEnumerator<int>
{
  private int _number;
  private int _exponent;
  private int _current = 1;

  public PowerEnumerator(int number, int exponent)
  {
    _number = number;
    _exponent = exponent;
  }

  public bool MoveNext()
  {
    _current *= number;
    return _exponent-- > 0;
  }

  public int Current
  {
    get
    {
      if (_exponent < 0) throw new InvalidOperationException();
      return _current;
    }
  }
}

Или что-то в этом роде. Это было не весело, позвольте мне сказать вам.

0 голосов
/ 13 января 2011
  1. Пусть .NET Reflector декомпилирует его. Это общее решение (на самом деле, конечный автомат), но довольно сложное,> 20 строк кода, если я правильно помню.
  2. Ленивый. Вот почему yield может быть весьма эффективным.
0 голосов
/ 13 января 2011
  1. Это будет пользовательская реализация IEnumerable<T>, не опирающаяся на существующую реализацию, такую ​​как List<T>
  2. Лениво.

Более подробная информация доступна здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...