C# の例(8)
Channel を使ったイテレーターのクラス IteratorChannelImpl を作成しました。「ConfigureAwait(false)」というのは「これがないと await の前後が同じスレッドで実行されるので Result を取得することができない」という仕様らしいです。意味がよくわからなくで気持ち悪いのですが、今回は複数スレッドで実行することが目的ではないので、この仕様に従うことにします。
internal class IteratorChannelImpl<T> { private Channel<T> ch_get; private T? current; public IteratorChannelImpl(Channel<T> ch_get) { this.ch_get = ch_get; } public T? Current { get { return current; } } private async Task<bool> GetFromServer_a() { if (!await ch_get.Reader.WaitToReadAsync().ConfigureAwait(false)) { return false; } if (!ch_get.Reader.TryRead(out current)) { return false; } return true; } private bool GetFromServer() { return GetFromServer_a().Result; } public bool MoveNext() { if (!GetFromServer()) { return false; } return true; } public IEnumerable<T?> Take(int count) { IteratorChannelImpl<T> it = this; for (int i = 0; i < count && it.MoveNext(); i++) { yield return it.Current; } } }
private void button3_Click(object sender, EventArgs e) { IteratorClass iterator = new IteratorClass(); Channel<int> ch_get = Channel.CreateBounded<int>(1); Task task = Task.Run(() => iterator.Generator(ch_get)); IteratorChannelImpl<int> iter = new IteratorChannelImpl<int>(ch_get); string res = ""; while (iter.MoveNext()) { res += iter.Current.ToString() + " "; } textBox1.Text = res; }
実行結果: 0 1 2 3 4 5 6 7 8 9
仮想サーバーへの get と set の両方があるイテレーターのクラス IteratorChannelIOImpl は以下のようになります。
internal class IteratorChannelIOImpl<T> { private Channel<T> ch_get; private Channel<T> ch_set; private T? current; public IteratorChannelIOImpl(Channel<T> ch_get, Channel<T> ch_set) { this.ch_get = ch_get; this.ch_set = ch_set; GetFromServer(); // 最初の値を取得 } public T? Current { get { return current; } set { current = value; } } private async Task<bool> GetFromServer_a() { if (!await ch_get.Reader.WaitToReadAsync().ConfigureAwait(false)) { return false; } if (!ch_get.Reader.TryRead(out current)) { return false; } return true; } private bool GetFromServer() { return GetFromServer_a().Result; } private async Task<bool> SetToServer_a() { if (!await ch_set.Writer.WaitToWriteAsync().ConfigureAwait(false)) { return false; } if (!ch_set.Writer.TryWrite(current)) { return false; } return true; } private bool SetToServer() { return SetToServer_a().Result; } public bool MoveNext() { if (!SetToServer()) { return false; } if (!GetFromServer()) { return false; } return true; } public IEnumerable<T?> Take(int count) { IteratorChannelIOImpl<T> it = this; for (int i = 0; i < count && it.MoveNext(); i++) { yield return it.Current; } } }
private void button4_Click(object sender, EventArgs e) { IteratorClass iterator = new IteratorClass(); Channel<int> ch_get = Channel.CreateBounded<int>(1); Channel<int> ch_set = Channel.CreateBounded<int>(1); Task task = Task.Run(() => iterator.GeneratorIO(ch_get, ch_set)); IteratorChannelIOImpl<int> iter = new IteratorChannelIOImpl<int>(ch_get, ch_set); string res = ""; while (iter.MoveNext()) { res += iter.Current.ToString() + " "; iter.Current = iter.Current * 2; } textBox1.Text = res; }
実行結果: 1 2 4 8 16 32 64 128 256
前回より1個少なくなりましたが良しとします。