5

async / awaitに関するstackoverflowに関する以前の質問の後、awaitは、マーケティングが提案したよりもはるかに強力で一般的であるように思われました。F#と同じように、計算式を作成する一般的な方法のようです。それで、少し苦労した後、私は以下のように正常に実行されるいくつかのコードを思いつきました。

    using FluentAssertions;
    using System.Collections.Generic;

    namespace EnumerableViaAwait.Specs
    {
        [global::Microsoft.VisualStudio.TestTools.UnitTesting.TestClass]
        public class MyTestClass
        {
            public IEnumerable<int> Numbers()
            {
                return EnumeratorMonad.Build<int>(async Yield =>
                {
                    await Yield(11);
                    await Yield(22);
                    await Yield(33);
                });
            }

            [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod]
            public void TestEnum()
            {
                var v = Numbers();
                var e = v.GetEnumerator();

                int[] expected = { 11, 22, 33 };

                Numbers().Should().ContainInOrder(expected);

            }

        }
    }

ここで何が起こっているかに注意深く注意してください。私はリアクティブオブザーバブルを構築していません。IEnumerableを構築しています。厳密にはプルシステムです。とても楽しく書けます。

    foreach item in Numbers(){
            Console.WriteLine(item);
    }

そしてそれは印刷されます

    11
    22
    33

システムは厳密には非同期ではないため、これは非常に興味深いものですが、ここで概説するように、awaitフレームワークと「何でも待つ」機能を悪用しています。http://blogs.msdn.com/b/pfxteam/archive/2011/01/13/10115642.aspx 。 質問は次のとおりです。

  1. このawait/asyncの乱用はどこまで進むことができますか?
  2. このパターンはF#の計算式と同じくらい強力ですか?
  3. 従来のIEnumerator/Yieldパターンは、このパターンに正確に評価される単なる構文糖衣です

パターンを実装するコードは以下のとおりです

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Threading.Tasks;

    namespace EnumerableViaAwait
    {

        public class EnumeratorMonad<T> : IEnumerable<T>, IEnumerator<T>
        {
            public class Yield
            {
                private EnumeratorMonad<T> _Monad;

                public Yield(EnumeratorMonad<T> monad)
                {
                    _Monad = monad;
                }

                public YieldAwaiter GetAwaiter()
                {
                    return new YieldAwaiter(_Monad);
                }
            }

            public class YieldAwaiter : INotifyCompletion
            {
                EnumeratorMonad<T> _Monad;

                public YieldAwaiter(EnumeratorMonad<T> monad)
                {
                    _Monad = monad;
                }

                public bool IsCompleted
                {
                    get { return _Monad.IsCompleted(); }
                }

                public void GetResult()
                { }

                public void OnCompleted(Action continuation)
                {
                    _Monad.Next = continuation; 
                }

            }

            private bool Completed { get; set; }

            public EnumeratorMonad()
            {
                Completed = false;
            }

            public bool IsCompleted()
            {
                return Completed;
            }

            public void Build(Func<Func<T, Yield>, Task> action)
            {
                Func<T, Yield> yielder = (T value) => { 
                    _Current = value;
                    return new Yield(this);
                };
                Next = async () => { 
                    await action(yielder);
                    Completed = true;
                };
            }

            private T _Current;
            public T Current
            {
                get { return _Current; }
            }

            public void Dispose()
            {
            }

            object System.Collections.IEnumerator.Current
            {
                get { return _Current; }
            }


            Action Next;
            public bool MoveNext()
            {
                if (!Completed )
                {
                    Next();
                }
                return !Completed;
            }

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



            IEnumerator<T> IEnumerable<T>.GetEnumerator()
            {
                return this;
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return this;
            }
        }

        public class EnumeratorMonad{
            public static EnumeratorMonad<T> Build<T>(Func<Func<T, EnumeratorMonad<T>.Yield>, Task> action)
            {
                var monad = new EnumeratorMonad<T>();
                monad.Build(action);
                return monad;
            }
        }

}

4

1 に答える 1

5

yield returnおよびawait/asyncは、コルーチンの異なる特殊な形式です。/yield returnを使用して(基本的に)実装できることを示しましたが、その逆が可能であることに気付いても驚かないでしょう。それらは非常によく似た方法で実装されていると確信しています。awaitasync

もちろん、実際には、await/asyncを反復に使用しません。これyield returnは、はるかに単純で明確だからです。

それで、

  1. あなたはおそらくあなたが望む限りこの「虐待」をとることができます。
  2. 答えるにはF#に十分な知識がありません。
  3. いいえ。ただし、IIRCの機能はほぼ同じ方法で実装されます。
于 2012-10-22T13:56:48.710 に答える