<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mingbo &#187; 委托</title>
	<atom:link href="http://shao.mingbo.de/tag/%e5%a7%94%e6%89%98/feed/" rel="self" type="application/rss+xml" />
	<link>http://shao.mingbo.de</link>
	<description>包括教育技术，编程，互联网等方面的文章及随想。</description>
	<lastBuildDate>Sun, 25 Jul 2010 05:18:53 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=abc</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>cSharp中异步委托的笔记</title>
		<link>http://shao.mingbo.de/2009/12/19/asynchronous-delegate-in-csharp/</link>
		<comments>http://shao.mingbo.de/2009/12/19/asynchronous-delegate-in-csharp/#comments</comments>
		<pubDate>Sat, 19 Dec 2009 12:13:33 +0000</pubDate>
		<dc:creator>邵 明博</dc:creator>
				<category><![CDATA[csharp-note]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[myNote]]></category>
		<category><![CDATA[委托]]></category>
		<category><![CDATA[异步]]></category>

		<guid isPermaLink="false">http://shao.mingbo.de/?p=392</guid>
		<description><![CDATA[异步委托，首先要搞明白，为什么要用到异步委托。
长时间以来，我个人在编写代码的时候，都认为程序应该是执行完一件事之后，然后再干接下来的。这用计算机术语来讲，叫同步执行（Synchronous Execution）。但事实上，这样的执行效果不一定人性化。举下面的一组对照：

你有3份快件需要传递给远程客户。如果这件事由你本人亲自完成，那么，接下来，你将要停下手中的工作，跑3段路程，分别将这3个快件递交给3个不同的客户。然后返回公司继续执行你手上剩下的工作。现实生活中，这样的事情或许永远不会发生，因为聪明的你会打一个电话叫来快递专员来为你解决快件问题。
刚入学那会，写了一个资源转换工具。那个时候还没意识到出现了这样的问题：当我执行转换的时候，UI 无法继续响应用户的操作，而只有当转换完毕之后才恢复正常。实际上，现在分析起来，就是主线程没空搭理你，它正忙，忙完之后才能执行你的更新的操作。这个处境和之前的那个跑3段路传递3个快件的境遇差不多。.net 为我们设计了这个异步委托来执行类似快递专员的工作。

搞懂异步委托，需要理解BeginInvoke() ,EndInvoke() ,IAsyncResult 以及AsyncCallback 委托:
异步委托提供以异步方式调用同步方法的能力。当同步调用一个委托时，“Invoke”方法直接对当前线程调用目标方法。如果编译器支持异步委托，则它将生成“Invoke”方法以及“BeginInvoke”和“EndInvoke”方法。如果调用“BeginInvoke”方法，则公共语言运行库 (CLR) 将对请求进行排队并立即返回到调用方。将对来自线程池的线程调用该目标方法。提交请求的原始线程自由地继续与目标方法并行执行，该目标方法是对线程池线程运行的。如果在对“BeginInvoke”方法的调用中指定了回调方法，则当目标方法返回时将调用该回调方法。在回调方法中，“EndInvoke” 方法获取返回值和所有输入/输出参数。如果在调用“BeginInvoke”时未指定任何回调方法，则可以从调用“BeginInvoke”的线程中调用“EndInvoke”。
下面，我用一个例子，谈谈可能发生的4种情况
    class Programe
    {
        private delegate void ADelegateSomewhat(int x);

        public static void Main()
        {
     [...]]]></description>
			<content:encoded><![CDATA[<p>异步委托，首先要搞明白，为什么要用到异步委托。</p>
<p>长时间以来，我个人在编写代码的时候，都认为程序应该是执行完一件事之后，然后再干接下来的。这用计算机术语来讲，叫同步执行（Synchronous Execution）。但事实上，这样的执行效果不一定人性化。举下面的一组对照：</p>
<ul>
<li>你有3份快件需要传递给远程客户。如果这件事由你本人亲自完成，那么，接下来，你将要停下手中的工作，跑3段路程，分别将这3个快件递交给3个不同的客户。然后返回公司继续执行你手上剩下的工作。现实生活中，这样的事情或许永远不会发生，因为聪明的你会打一个电话叫来快递专员来为你解决快件问题。</li>
<li>刚入学那会，写了一个<a href="http://shao.mingbo.de/2009/10/10/ipv6-web-auto-adaptation/">资源转换工具</a>。那个时候还没意识到出现了这样的问题：当我执行转换的时候，UI 无法继续响应用户的操作，而只有当转换完毕之后才恢复正常。实际上，现在分析起来，就是主线程没空搭理你，它正忙，忙完之后才能执行你的更新的操作。这个处境和之前的那个跑3段路传递3个快件的境遇差不多。.net 为我们设计了这个<strong>异步委托</strong>来执行类似快递专员的工作。</li>
</ul>
<p>搞懂<strong>异步委托</strong>，需要理解<strong>BeginInvoke() </strong>,<strong>EndInvoke()</strong> ,<strong>IAsyncResult</strong> 以及<strong>AsyncCallback</strong> 委托:</p>
<blockquote><p>异步委托提供以异步方式调用同步方法的能力。当同步调用一个委托时，“Invoke”方法直接对当前线程调用目标方法。如果编译器支持异步委托，则它将生成“Invoke”方法以及“BeginInvoke”和“EndInvoke”方法。如果调用“BeginInvoke”方法，则公共语言运行库 (CLR) 将对请求进行排队并立即返回到调用方。将对来自线程池的线程调用该目标方法。提交请求的原始线程自由地继续与目标方法并行执行，该目标方法是对线程池线程运行的。如果在对“BeginInvoke”方法的调用中指定了回调方法，则当目标方法返回时将调用该回调方法。在回调方法中，“EndInvoke”<strong> </strong>方法获取返回值和所有输入/输出参数。如果在调用“BeginInvoke”时未指定任何回调方法，则可以从调用“BeginInvoke”的线程中调用“EndInvoke”。</p></blockquote>
<p>下面，我用一个例子，谈谈可能发生的4种情况</p>
<pre name="code" class="c-sharp">    class Programe
    {
        private delegate void ADelegateSomewhat(int x);

        public static void Main()
        {
            ADelegateSomewhat aD = MathPupil;
            ////1.直接调用EndInvoke,这和直接调用MathPupil(100)的效果一样，
            ////但会等到这个方法执行完之后才去执行后面的语句
            //IAsyncResult ar= aD.BeginInvoke(100,null,null);
            //aD.EndInvoke(ar);

            ////2.轮询,每隔50毫秒看看孩子算完了没.
            //IAsyncResult ar = aD.BeginInvoke(200, null, null);
            //while (!ar.IsCompleted)
            //{
            //    Console.Write(".");
            //    Thread.Sleep(500);
            //}
            //aD.EndInvoke(ar);

            ////3.实际上和2的方法类似，只是把Sleep的时间放上来了
            ////但事实上，功能会多点,比如控制跳出的条件等
            //IAsyncResult ar = aD.BeginInvoke(300,null,null);
            //while (!ar.AsyncWaitHandle.WaitOne(500))
            //{
            //    Console.Write(".");
            //}
            //aD.EndInvoke(ar);

            //4.回调函数,最有意义,设置相对麻烦点
            IAsyncResult ar = aD.BeginInvoke(400, MathCallBack, aD);
            //现在干点别的事，不用关心算算术题的孩子了。
            //由delegate的回调方法自动来管理
            Console.ReadLine();
            //如果不等待委托完成其任务就结束主线程，委托线程就会停止
        }

        //假装自己一个小学生处理一道加法算术题，历时5秒钟
        static void MathPupil(int x)
        {
            Console.WriteLine("Now I'll pretend to be a pupil");
            int sum = 0;
            for (int i = 0; i &lt; x; i++)
            {
                sum += i;
                Thread.Sleep(5000/x);
            }
            Console.WriteLine("After 5 secends, i've got the answer :" +sum);
        }

        static void MathCallBack(IAsyncResult ar)
        {
            ADelegateSomewhat aD = (ADelegateSomewhat)ar.AsyncState;
            aD.EndInvoke(ar);
        }

    }</pre>
<p>我想，到目前为止，应该收回<a href="http://shao.mingbo.de/2009/12/02/customize-event-in-csharp/">之前提到委托</a>“从来不是一个重点”的言论了。</p>
<p>参考资料：<a href="http://msdn.microsoft.com/en-us/magazine/cc164036.aspx" target="_blank">&lt;MSDN-magazine&gt;:Asynchronous Method Execution Using Delegates</a></p>
]]></content:encoded>
			<wfw:commentRss>http://shao.mingbo.de/2009/12/19/asynchronous-delegate-in-csharp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>cSharp中委托和事件的学习笔记</title>
		<link>http://shao.mingbo.de/2009/12/02/customize-event-in-csharp/</link>
		<comments>http://shao.mingbo.de/2009/12/02/customize-event-in-csharp/#comments</comments>
		<pubDate>Wed, 02 Dec 2009 10:03:33 +0000</pubDate>
		<dc:creator>邵 明博</dc:creator>
				<category><![CDATA[csharp-note]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[myNote]]></category>
		<category><![CDATA[事件]]></category>
		<category><![CDATA[委托]]></category>

		<guid isPermaLink="false">http://shao.mingbo.de/?p=343</guid>
		<description><![CDATA[运算符重载那一章的内容，等整理完了再稍后奉上。首先，让我趁热打铁的把委托和事件的笔记写完。不得不说，看到这里，觉得《Professional C#2008》这本书写的够烂的了。一个排序比较的例子，从接口那一章用到了委托，实在有点牵强，虽然一个比较算法用委托来定义是有效的，但把一个比较的能力看做是一个对象所拥有的属性更为恰当。当然，作者这样安排书的内容，无疑让我们可以看到：接口和委托都是允许类设计器分离声明和实现的。那么什么时候该用委托，什么时候该用接口呢？下面给出微软的一些我觉得还不错的建议。
以下几种情况比较适合委托：

当使用事件设计模式时；
当封装静态方式调用时；
当需要一个方法的多个实现时；（多播委托）
当调用一个实例方法而它不需要使用该实例的其他属性，方法，字段时；（独立性）

以下情况比较适合接口：

当方法和类型的能力挂钩时；（如类的自我比较能力IComparable）
当有一组可能被调用的相关方法时；（它们可能参数类型各不相同）
当类只需要方法的单个实现时；

委托从来不是一个重点，但委托，总是和事件联系紧密，再提到事件之前，必须要对他进行一个小小的知识梳理和补充。
委托：

委托实现了类似于c++ 中的函数指针，它包含的只是方法的地址，它可以将方法作为参数进行传递，它很安全
委托在c#2.0中使用了委托推断（允许不用new了），实现了匿名方法，在c#3.0中加入了Lambda 表达式，利用它们可以更简练地编写内联代码块
多播委托，其签名必须返回为void，否则就只能得到最后一个方法的结果
多播委托中，一个方法抛出异常，整个迭代会被终止；使用GetInvocationList()，来进行手动迭代
协变是允许方法的返回类型为派生类；抗变是运行方法的参数类型为派生类

谈完了委托，现在该来说说我们关心的事件。

事件的发行者决定什么时候引发事件，而订户决定怎么来响应事件；
一个事件可以有多个订户，一个订户可以响应多个事件；
一个事件可以引发多个订户同时响应，事件可以同步线程（当然也可以异步调用）；
没有订户的事件永远不会发生

在编写代码的过程中，实现一个事件，会遇到下面的几个层次：

订阅和取消
实现符合.net Framework 标准的事件(EventHandler&#38; EventArgs)
实现继承关系中的事件设计
实现接口关系中的事件设计
在字典中实现事件的设计（暂未接触字典方面的知识）

下面，我想给出一个自己写的继承关系中的事件设计demo：

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace learningLab
{
    class growUPEventArgs:EventArgs
    {
        public string Message {get;set;}
        public growUPEventArgs(string message)
        {
      [...]]]></description>
			<content:encoded><![CDATA[<p>运算符重载那一章的内容，等整理完了再稍后奉上。首先，让我趁热打铁的把<strong>委托和事件</strong>的笔记写完。不得不说，看到这里，觉得《Professional C#2008》这本书写的够烂的了。一个排序比较的例子，从接口那一章用到了委托，实在有点牵强，虽然一个比较算法用委托来定义是有效的，但把一个比较的能力看做是一个对象所拥有的属性更为恰当。当然，作者这样安排书的内容，无疑让我们可以看到：接口和委托都是允许类设计器分离声明和实现的。那么什么时候该用委托，什么时候该用接口呢？下面给出微软的一些我觉得还不错的建议。</p>
<p>以下几种情况比较适合<strong>委托</strong>：</p>
<ol>
<li>当使用事件设计模式时；</li>
<li>当封装静态方式调用时；</li>
<li>当需要一个方法的多个实现时；（多播委托）</li>
<li>当调用一个实例方法而它不需要使用该实例的其他属性，方法，字段时；（独立性）</li>
</ol>
<p>以下情况比较适合接口：</p>
<ol>
<li>当方法和类型的能力挂钩时；（如类的自我比较能力IComparable）</li>
<li>当有一组可能被调用的相关方法时；（它们可能参数类型各不相同）</li>
<li>当类只需要方法的单个实现时；</li>
</ol>
<p>委托从来不是一个重点，但委托，总是和事件联系紧密，再提到事件之前，必须要对他进行一个小小的知识梳理和补充。</p>
<p>委托：</p>
<ul>
<li>委托实现了类似于c++ 中的函数指针，它包含的只是方法的地址，它可以将方法作为参数进行传递，它很安全</li>
<li>委托在c#2.0中使用了委托推断（允许不用new了），实现了匿名方法，在c#3.0中加入了Lambda 表达式，利用它们可以更简练地编写内联代码块</li>
<li>多播委托，其签名必须返回为void，否则就只能得到最后一个方法的结果</li>
<li>多播委托中，一个方法抛出异常，整个迭代会被终止；使用GetInvocationList()，来进行手动迭代</li>
<li>协变是允许方法的返回类型为派生类；抗变是运行方法的参数类型为派生类</li>
</ul>
<p>谈完了委托，现在该来说说我们关心的事件。</p>
<ul>
<li>事件的发行者决定什么时候引发事件，而订户决定怎么来响应事件；</li>
<li>一个事件可以有多个订户，一个订户可以响应多个事件；</li>
<li>一个事件可以引发多个订户同时响应，事件可以同步线程（当然也可以异步调用）；</li>
<li>没有订户的事件永远不会发生</li>
</ul>
<p>在编写代码的过程中，实现一个事件，会遇到下面的几个层次：</p>
<ul>
<li>订阅和取消</li>
<li>实现符合.net Framework 标准的事件(EventHandler&amp; EventArgs)</li>
<li>实现继承关系中的事件设计</li>
<li>实现接口关系中的事件设计</li>
<li>在字典中实现事件的设计（暂未接触字典方面的知识）</li>
</ul>
<p>下面，我想给出一个自己写的继承关系中的事件设计demo：</p>
<pre name="code" class="c-sharp">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace learningLab
{
    class growUPEventArgs:EventArgs
    {
        public string Message {get;set;}
        public growUPEventArgs(string message)
        {
            this.Message=message;
        }
    }

    abstract class person
    {
        private string _name;
        private int _age;

        public string Name
        {
            get
            {
                return _name;
            }
        }

        public int Age
        {
            get
            {
                return _age;
            }
        }

        public person(string name,int age)
        {
            this._age = age;
            this._name = name;

        }

        //这里并没有使用委托而是使用了泛型的EventHandler，可以节约一行代码
        public event EventHandler<growUPEventArgs> GrowUPEvent;

        protected virtual void OnGrowUp(growUPEventArgs e)
        {
            //handler是一个临时变量，防止被一个竞争占用
            EventHandler<growUPEventArgs> handler = GrowUPEvent;
            //若handler不为空，则发行一个事件,this就是发行者person
            if (handler != null)
            {
                handler(this, e);
            }
        }
        // 定义一个方法来触发事件
       public abstract void growUp();
    }

    class student : person
    {
        public student(string name, int age) : base(name, age) { }

       protected override void OnGrowUp(growUPEventArgs e)
       {
           base.OnGrowUp(e);
       }

       public override void growUp()
       {
           this.OnGrowUp(new growUPEventArgs("Yeah,I'm getting older!"));
           //throw new NotImplementedException();
       }

    }

    class teacher : person
    {
        public teacher(string name, int age) : base(name, age) { }

        protected override void OnGrowUp(growUPEventArgs e)
        {
            base.OnGrowUp(e);
        }

        public override void growUp()
        {
            this.OnGrowUp(new growUPEventArgs("Oh,NO!I'm getting older!"));
            //throw new NotImplementedException();
        }
    }

    class InAclassRoom
    {
        private  List
<person> _PersonList;

        public InAclassRoom()
        {
            _PersonList=new List
<person>();
        }

        public void addPeople(person p)
        {
            _PersonList.Add(p);
            p.GrowUPEvent += HandlerYourGrowUp;

        }

        private void HandlerYourGrowUp(object o,growUPEventArgs e)
        {
            Console.WriteLine(e.Message);
        }

        public List
<person> getThePersonList()
        {
            return _PersonList;
        }
    }

    class Program
    {
        public static void Main()
        {
            teacher t = new teacher("MicroTeach", 40);
            student s = new student("Shaomingbo", 23);
            InAclassRoom classRoom = new InAclassRoom();
            classRoom.addPeople(t);
            classRoom.addPeople(s);
            //订阅了事件，但未触发。按回车后，方可触发;
            //此处说明了，事件发行者决定事件<何时发生>
            Console.WriteLine("You decide:<Enter>");
            Console.ReadLine();
            List
<person> plist = classRoom.getThePersonList();
            foreach (person p in plist)
            {
                Console.WriteLine("Hi, My Name is " + p.Name + ",and i'm " + p.Age + " years old.");
                Console.WriteLine("Actually ,i'm a " + p.GetType());
                Console.WriteLine("When I feel getting older,i'd say :");
                p.growUp();
                Console.WriteLine();
            }
            Console.ReadLine();
        }
    }
}
/*Output:
You decide:<Enter>

Hi, My Name is MicroTeach,and i'm 40 years old.
Actually ,i'm a learningLab.teacher
When I feel getting older,i'd say :
Oh,NO!I'm getting older!

Hi, My Name is Shaomingbo,and i'm 23 years old.
Actually ,i'm a learningLab.student
When I feel getting older,i'd say :
Yeah,I'm getting older!
*/
</pre>
<p>接口层次的设计，其实也应该来写写。但，由于还欠了好多笔记没整理暂时先停在这里。其中值得一提的是，一个类似于属性的事件访问器。其他的和继承实现没太多区别。</p>
]]></content:encoded>
			<wfw:commentRss>http://shao.mingbo.de/2009/12/02/customize-event-in-csharp/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
