• yield实现迭代以及APM


      yield关键字用于迭代器块中用于枚举数提供值或发出一个迭代结束标识,它只能出现在iterator块中。

    先看看一个传统迭代器的编写:

    Node结点类
    1 public class Node
    2 {
    3 public object data;
    4 public Node next;
    5
    6 public override string ToString()
    7 {
    8 return data.ToString();
    9 }
    10 }

    自定义一个集合并可枚举:

    Node集合类
    public class NodeCollection : IEnumerable<Node>
    {

    private Node[] nodes;
    private int index;
    private int capacity;

    public NodeCollection(int capacity)
    {
    nodes
    = new Node[capacity];
    index
    = 0;
    this.capacity = capacity;
    }

    public Node this[int _index]
    {
    get
    {
    return nodes[_index];
    }

    }

    public void Add(Node node)
    {
    if (index > capacity - 1)
    {
    throw new ArgumentException("run out of capacity");
    }
    nodes[index
    ++] = node;
    }

    #region IEnumerable<Node> Members

    public IEnumerator<Node> GetEnumerator()
    {
    return new NodeEnumerator(nodes);
    }

    #endregion

    }
    该集合是的迭代器是用传统方法来实现的,需要实现:IEnumerator<>

    Node集合枚举器
    1 public class NodeEnumerator : IEnumerator<Node>
    2 {
    3 public Node[] nodes;
    4 int index;
    5
    6 public NodeEnumerator(Node[] _nodes)
    7 {
    8 this.nodes = new Node[_nodes.Length];
    9 _nodes.CopyTo(nodes, 0);
    10 index = -1;
    11 }
    12
    13 #region IEnumerator<Node> Members
    14
    15 public Node Current
    16 {
    17 get
    18 {
    19 return nodes[index];
    20 }
    21 }
    22
    23 #endregion
    24
    25 #region IDisposable Members
    26
    27 public void Dispose()
    28 {
    29 nodes = null;
    30 }
    31
    32 #endregion
    33
    34 #region IEnumerator Members
    35
    36 object System.Collections.IEnumerator.Current
    37 {
    38 get { return nodes[index]; }
    39 }
    40
    41 public bool MoveNext()
    42 {
    43 index++;
    44 if (index < nodes.Length)
    45 {
    46 return true;
    47 }
    48 else
    49 {
    50 return false;
    51 }
    52 }
    53
    54 public void Reset()
    55 {
    56 index = -1;
    57 }
    58
    59 #endregion
    60 }

    看得出来很繁锁,这在.net 1.1框架的做法,1.1之后不需要这么做,直接用yield关键字搞定一切,看代码:

    yield的枚举器
    1 public IEnumerator<Node> GetEnumerator()
    2 {
    3 //return new NodeEnumerator(nodes);
    4   for (int i = 0; i < capacity; i++)
    5 {
    6 yield return nodes[i];
    7 }
    8 }
    非常简单,这完全符合MS的原则:Write less code,Do more things

    再看看得用这yield关键字改变传统的APM编程模型,通常利用传统异步编程模型的都是一个BeginXXX(AsyncCallback)的时候,然后EndXXX(IAsyncResult),程序写起来流畅,因为老是要写callback函数,要做的的事其实要让BeginXXX完成后,直接yield return number 返回一个得用枚举器中断当前线程,当BeginXXX()操作完成后,只需要在它的回调函数完成一次MoveNext()操作再执行yield return number之后的代码,这时候其实现就调用 EndXXX来完成本次异步调用,看代码

    下载
    1 static void Main()
    2 {
    3 DownloadContext context = new DownloadContext();
    4 AsyncDownload download = new AsyncDownload();
    5 context.Start(download.Download(context));
    6
    7 Console.Read();
    8 }
    9
    10 public IEnumerator<int> Download(DownloadContext context)
    11 {
    12 var request = HttpWebRequest.Create("http://www.baidu.com");
    13 var ar = request.BeginGetResponse(context.Continue(), null);
    14 yield return 1;
    15 var response = request.EndGetResponse(ar);
    16
    17 byte[] buffer = new byte[1024];
    18 using (Stream sr = response.GetResponseStream())
    19 using(StreamReader sr = new StreamReader(response.GetResponseStream()))
    20 {
    21 //Console.WriteLine(sr.ReadToEnd());
    22 var ar2 = sr.BeginRead(buffer, 0, buffer.Length, context.Continue(), null);
    23 //Console.WriteLine(BitConverter.ToString(buffer));
    24 yield return 1;
    25 sr.EndRead(ar2);
    26 }
    27 }
    28 }
    29
    30 public class DownloadContext
    31 {
    32 private IEnumerator<int> enumerator;
    33
    34 public AsyncCallback Continue()
    35 {
    36 return (ar) => enumerator.MoveNext();
    37 }
    38
    39 public void Start(IEnumerator<int> enumerator)
    40 {
    41 this.enumerator = enumerator;
    42 enumerator.MoveNext();
    43 }
    44 }

    这里有更详细的介绍关于APM编程的:http://www.cnblogs.com/yuyijq/archive/2011/02/24/1963326.html

    我借鉴了作者的思路 ,自己再理一下,其实都是些老掉牙的技术了,手痒的时候再写一遍未尝不是一件好事!

  • 相关阅读:
    Java中同步
    Java多线程
    Java中的instanceof关键字
    Java多态与C++中多态的实现
    Java中的接口
    Java中的抽象类
    Java单链表的实现
    Java中的内部类
    memcached telnet command
    The CHECK_POLICY and CHECK_EXPIRATION options cannot be turned OFF when MUST_CHANGE is ON. (Microsoft SQL Server,错误: 15128)
  • 原文地址:https://www.cnblogs.com/repository/p/2026332.html
Copyright © 2020-2023  润新知