﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-KiMoGiGi 技术文集-文章分类-C#</title><link>http://www.cnitblog.com/seeyeah/category/6315.html</link><description>不在乎选择什么，而在乎坚持多久……</description><language>zh-cn</language><lastBuildDate>Tue, 27 Sep 2011 20:10:00 GMT</lastBuildDate><pubDate>Tue, 27 Sep 2011 20:10:00 GMT</pubDate><ttl>60</ttl><item><title>To 王涛 的问题</title><link>http://www.cnitblog.com/seeyeah/articles/46094.html</link><dc:creator>KiMoGiGi</dc:creator><author>KiMoGiGi</author><pubDate>Sat, 28 Jun 2008 14:47:00 GMT</pubDate><guid>http://www.cnitblog.com/seeyeah/articles/46094.html</guid><wfw:comment>http://www.cnitblog.com/seeyeah/comments/46094.html</wfw:comment><comments>http://www.cnitblog.com/seeyeah/articles/46094.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/seeyeah/comments/commentRss/46094.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/seeyeah/services/trackbacks/46094.html</trackback:ping><description><![CDATA[<p>王涛：<br><br>你好。<br><br>本人想请教一个关于字符串驻留机制的问题，希望您有空可以解答。</p>
<p><br>请先看以下代码</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s1&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">abc</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s2&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">a</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>s2&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bc</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>Console.WriteLine(</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">.IsInterned(s2)&nbsp;</span><span style="COLOR: #000000">??</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">null</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);</span></div>
<p><br>返回的结果为abc，这是正常情况。</p>
<p>如果我改一下，s1的声明位置。<br><br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s2&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">a</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>s2&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bc</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>Console.WriteLine(</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">.IsInterned(s2)&nbsp;</span><span style="COLOR: #000000">??</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">null</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s1&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">abc</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;</span></div>
<p>&nbsp;</p>
<p>显示结果还是abc。<br><br>无论debug跟踪，还是看IL，"abc"赋值于s1都是在string.IsInterned(s2)判断之后，那么为什么判断结果不是null？</p>
<p>难道对于字符串驻留是在编译期完成？如果不是，那跟方法内的声明顺序有关？局部变量第一次声明代码无论在哪里，都是在方法的一开始进行？<br><br>无论局部变量s1初始声明位于什么地方，执行方法的时候都是在一开始给他初始化？</p>
<p>但如果代码改为：</p>
<p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;Main(</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">[]&nbsp;args)<br>{<br>&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s2&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">a</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;s2&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bc</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;Console.WriteLine(</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">.IsInterned(s2)&nbsp;</span><span style="COLOR: #000000">??</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">null</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s1&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;Test();<br>}<br><br></span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;Test()<br>{<br>&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">abc</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>}<br></span></div>
<p>&nbsp;</p>
<p>即显示null，又不是abc了。<br></p>
<br>又换个角度，如果把局部变量变为全局变量会怎样？<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">abc</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br><br>&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;Main(</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">[]&nbsp;args)<br>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s2&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">a</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s2&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bc</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">.IsInterned(s2)&nbsp;</span><span style="COLOR: #000000">??</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">null</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;}<br></span></div>
<p>&nbsp;</p>
<p>结果返回null。另一个问题出来了，常量不也是&#8220;静态变量&#8221;（如果把s改为静态类型，结果返回"abc"）?为什么返回null？<br><br><br>具体问题：<br>1、怎么解释上面代码出现的现象。<br>2、究竟方法内局部变量的初始化具体如何执行？从IL看不出什么端倪。<br><br>希望Anytao可以抽空帮我解释一下，回复本帖或者发邮件给我都可以，谢谢。</p>
<img src ="http://www.cnitblog.com/seeyeah/aggbug/46094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/seeyeah/" target="_blank">KiMoGiGi</a> 2008-06-28 22:47 <a href="http://www.cnitblog.com/seeyeah/articles/46094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[2007-12-1]异步调用方法 </title><link>http://www.cnitblog.com/seeyeah/articles/36862.html</link><dc:creator>KiMoGiGi</dc:creator><author>KiMoGiGi</author><pubDate>Sun, 25 Nov 2007 13:32:00 GMT</pubDate><guid>http://www.cnitblog.com/seeyeah/articles/36862.html</guid><wfw:comment>http://www.cnitblog.com/seeyeah/comments/36862.html</wfw:comment><comments>http://www.cnitblog.com/seeyeah/articles/36862.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/seeyeah/comments/commentRss/36862.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/seeyeah/services/trackbacks/36862.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 原文标题：Asynchronous Method Invocation作者：mikeperetz链接：http://www.codeproject.com/csharp/AsyncMethodInvocation.asp 翻译开始时间：2007-11-27&nbsp;简介在此篇文章，我将要解释异步方法的调用以及如何使用它们。在玩过委托、线程和异步调用一段时间后，如果我不分享一下我在这些...&nbsp;&nbsp;<a href='http://www.cnitblog.com/seeyeah/articles/36862.html'>阅读全文</a><img src ="http://www.cnitblog.com/seeyeah/aggbug/36862.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/seeyeah/" target="_blank">KiMoGiGi</a> 2007-11-25 21:32 <a href="http://www.cnitblog.com/seeyeah/articles/36862.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[2007-11-26]使用依赖注入解耦</title><link>http://www.cnitblog.com/seeyeah/articles/36861.html</link><dc:creator>KiMoGiGi</dc:creator><author>KiMoGiGi</author><pubDate>Sun, 25 Nov 2007 13:30:00 GMT</pubDate><guid>http://www.cnitblog.com/seeyeah/articles/36861.html</guid><wfw:comment>http://www.cnitblog.com/seeyeah/comments/36861.html</wfw:comment><comments>http://www.cnitblog.com/seeyeah/articles/36861.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/seeyeah/comments/commentRss/36861.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/seeyeah/services/trackbacks/36861.html</trackback:ping><description><![CDATA[<p>原文<br>标题：Dependency Injection for Loose Coupling<br>作者：<a href="http://www.codeproject.com/script/Articles/list_articles.asp?userid=2797038"><strong><u><font color=#0000ff>Billy McCafferty</font></u></strong></a>. <br>链接：<a href="http://www.codeproject.com/cs/design/DependencyInjection.asp">http://www.codeproject.com/cs/design/DependencyInjection.asp</a><br>翻译开始时间：2007-11-25<br>
<hr>
<br>
<p><span style="COLOR: #993300"><strong style="FONT-SIZE: 18pt">简介</strong></span></p>
<p>在面向对象的设计中，有一个重要的原则 -- &#8220;解耦&#8221;。简单说（loosely），不是一语双关（这里使用loosely和loose coupling没有任何关系，只是语法相似），&#8220;解耦&#8221;的意思就是说，一个对象工作时需要依赖一些对象，而这些依赖应该越少越好。此外，当可能的时候，对象依赖的应该是接口，而不是具体具体化的类。(具体得累就是用关键字&#8220;new&#8221;常见的实例。）&#8220;解耦&#8221;能促进更好的重用、增加可维护性，并且允许你能很容易地提供&#8220;模仿&#8221;(Mock)对象替代昂贵的服务，例如端口交流器（socket-communicator）。</p>
<p>&#8220;依赖注入&#8221;（"Dependency Injection"，简称DI），和更神秘的概念&#8220;控制反转&#8221;（Inversion of Control" ，简称IoC），是一项提供解耦方式的技术。主要有两个实现DI的的方式：构造函数注入（constructor injection）和设置方法注入（setter injection）。显然，在某些点上，必须要&#8220;某个东西&#8221;有创建具体的类的职责，以提供对象，可供注入到另一个对象。这个注入者（injector）可以为一个父类，我们称为&#8220;依赖注入控制端&#8221;（DI controller）；或者能被一个&#8220;依赖注入容器&#8221;（DI container）在外部处理实现。以上就是几个主要的使用依赖注入的概观。</p>
<p><span style="FONT-SIZE: 18pt; COLOR: #993300"><strong>构造函数注入（Constructor Injection）</strong></span></p>
<p>使用构造函数参数传递对象依赖的DI（依赖注入以下都简称为DI）技术，就是构造函数注入。以下的这个例子，包括一个类，Customer,它暴露了一个方法去获得每份销售订单所属客户的详细日期信息。因此，Customer类需要一个数据访问类与数据库关联。假设，现在有一个类orderDao （全名"order data-access object"），实现接口IOrderDao.有一种方法，Customer类可以执行以下代码获得依赖：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">IOrderDao&nbsp;orderDao&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;OrderDao();</span></div>
<p>这样做，有2个主要的缺点。</p>
<p>1、在本地实例化OrderDao,就抵消了在一开始使用接口的好处；并且<br>2、OrderDao不能轻易地被用来测试的Mock对象替换。（Mock对象会稍后讨论）</p>
<p>上述的例子应该如下：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Customer&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;Customer(IOrderDao&nbsp;orderDao)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(orderDao&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;ArgumentNullException(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">orderDao&nbsp;may&nbsp;not&nbsp;be&nbsp;null</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.orderDao&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;orderDao;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;IList&nbsp;GetOrdersPlacedOn(DateTime&nbsp;date)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;<img src="http://www.cnitblog.com/Images/dot.gif">&nbsp;code&nbsp;that&nbsp;uses&nbsp;the&nbsp;orderDao&nbsp;member<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;orders&nbsp;from&nbsp;the&nbsp;datasource&nbsp;<img src="http://www.cnitblog.com/Images/dot.gif"></span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;IOrderDao&nbsp;orderDao;<br>}<br><br></span></div>
<p>在以上例子中，注意构造函数接受的是一个接口；不是接受一个具体的类。同时，注意如果orderDao参数为null的时候，抛出了异常。这样强调了获取依赖对象的合法性。以我的观点，构造函数注入，它最好的机制在于提供了对象必须的依赖。让开发这清楚地知道，调用Customer，在它能正常执行之前，需要提供哪些它所依赖的对象。然而，考虑以下状况&#8230;&#8230;假设你的类有十个方法都不需要依赖，但你加一个方法需要依赖于IOrderDao。你的确可以改动构造函数，使用构造函数注入，但这会强迫你在所有地方改变原有的构造函数调用。当然，你也可以选择新加一个构造函数老获取依赖，但怎么样能让开发简单地知道使用哪个构造函数呢？最后，如果这个依赖的创建是很昂贵的，为什么要创建它并传入构造函数类，然而却很少使用它？设置方法注入（setter injection）可以在这种情况下使用。<br><br><span style="FONT-SIZE: 18pt; COLOR: #993300"><strong>设置方法注入（Setter Injection）</strong></span></p>
<p>设置方法注入不会强迫传递依赖对象到构造函数中。取而代之，是通过对象暴露出来的公有方法设置依赖。这样做法的动机主要包括以下几点：</p>
<p>&nbsp;1、在继承的类中，无需修改构造函数，就可实现依赖注入，而且；<br>&nbsp;2、允许尽可能晚的，而且在需要的情况下，才创建某些昂贵的资源或服务。</p>
<p>以下代码使用设置方法注入替代刚才的构造函数注入：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Customer&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;Customer()&nbsp;{}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;IOrderDao&nbsp;OrderDao&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">set</span><span style="COLOR: #000000">&nbsp;{&nbsp;orderDao&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;value;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">get</span><span style="COLOR: #000000">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(orderDao&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;MemberAccessException(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">orderDao</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;has&nbsp;not&nbsp;been&nbsp;initialized</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;orderDao;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;IList&nbsp;GetOrdersPlacedOn(DateTime&nbsp;date)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><img src="http://www.cnitblog.com/Images/dot.gif">&nbsp;code&nbsp;that&nbsp;uses&nbsp;the&nbsp;OrderDao&nbsp;public<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><img src="http://www.cnitblog.com/Images/dot.gif">&nbsp;property&nbsp;to&nbsp;get&nbsp;orders&nbsp;from&nbsp;the&nbsp;datasource&nbsp;<img src="http://www.cnitblog.com/Images/dot.gif"></span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Should&nbsp;not&nbsp;be&nbsp;called&nbsp;directly;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;use&nbsp;the&nbsp;public&nbsp;property&nbsp;instead</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;IOrderDao&nbsp;orderDao;<br>}</span></div>
<p><br>在以上的例子中，构造函数没有参数。替代的是，在调用对象时，执行GetOrdersPlacedOn方法之前需要先设置IOrderDao依赖。构造函数注入而言，当依赖一开始没有注入时，程式立刻会抛出异常。例如，创建对象之前。对于设置方法注入而言，异常要到某个方法要使用依赖时才会抛出。还有注意的是，GetOrdersPlacedOn方法使用的是OrderDao属性，而不是直接使用私有的orderDao变量。这样，属性的getter方法才有机会验证依赖对象是否初始化。</p>
<p>使用设置方法注入替换构造函数注入时要谨慎，因为：</p>
<p>1、至少到&#8220;has not been initialized&#8221;抛出异常的时候，开发人员要清楚哪些依赖是需要的；<br>2、加大了一点难度去跟踪异常的来源和原因。</p>
<p>虽然如此，设置方法注入能提供新方法的同时尽量少改动原有的代码；如果所依赖的对象创建时非常昂贵或很困难的，此注入方法能提供性能上的加速。<br><br><span style="FONT-SIZE: 18pt; COLOR: #993300"><strong>注入器（The Injectors）</strong></span><br><br>紧接着，下一个问题就是，什么东西能创建出依赖对象，注入到&#8220;被注入者&#8221;？有2个试点那个的地方以供创建这些逻辑：控制器和容器。<br><br><strong>DI 控制器（DI Controllers）<br><br></strong>DI控制器的创建步骤是容易理解和实现的。在一个适当分层的架构中，一个应用程式拥有不同的层处理逻辑。最简单的分层通常包括与数据库通讯的数据层，负责显示UI的表现层，履行业务逻辑的区域逻辑层。即使没有很好地定义,&#8220;控制器&#8221;层总是存在，为了定位UI事件到区域和数据层，反之亦然。举个例子，在ASP.NET中，code-behind页面扮演基础控制层。还有更多形式化的控制层存在：Java中的Struts和Spring;.NET的Front Controller 和 Spring .NET 。全部这些实现都遵守着MVC（Model-View-Controller ）模式形态。不管你用什么作为你的控制器，这个控制器就是实现依赖注入配件的适合所在；这里是实例化、注入依赖对象的地方。接着两个例子演示使用控制器实现DI。第一个例子是一个示例性的例子 &#8220;生成注入代码&#8221;-- 你要自我完成配置。第二个是&#8220;测试代码&#8221;示例 -- 用来测试应用程式的，但没有完整，并不一定需要一个真实的数据库。<br><br>控制器代码实现依赖注入（如，ASP.NET code-behind页面）：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><img src="http://www.cnitblog.com/Images/dot.gif">&nbsp;code&nbsp;performed&nbsp;when&nbsp;the&nbsp;controller&nbsp;is&nbsp;loaded&nbsp;<img src="http://www.cnitblog.com/Images/dot.gif"></span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>IOrderDao&nbsp;orderDao&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;OrderDao();<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Using&nbsp;Setter&nbsp;Injection&nbsp;on&nbsp;a&nbsp;pre-existing&nbsp;customer</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">someCustomer.OrderDao&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;orderDao;<br>IList&nbsp;ordersPlacedToday&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;someCustomer.GetOrdersPlacedOn(DateTime.Now);<br><br><img src="http://www.cnitblog.com/Images/dot.gif"></span></div>
<br>单元测试的依赖注入：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">IOrderDao&nbsp;orderDao&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;MockOrderDao();<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Using&nbsp;Setter&nbsp;Injection&nbsp;on&nbsp;a&nbsp;pre-existing&nbsp;customer</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">someCustomer.OrderDao&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;orderDao;<br>IList&nbsp;ordersPlacedToday&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;someCustomer.GetOrdersPlacedOn(DateTime.Now);</span></div>
<p><br>使用DI控制器注入以来的一个主要好处就是它非常直接、容易地指出创建在何处发生。缺点就是仍然在某处存在依赖的硬编码；即使硬编码处于经常需要变动的位置。另一个缺点在于，现在DI控制器无法轻易地使用mock对象进行单元测试。（但我承认，某些强大的工具如<a href="http://www.typemock.com/">TypeMock</a>，可以在任何情况下生成注入mock对象。但是，类似TypeMock的工具应该只是用在绝对必要的情况下，因为他们引导你不使用&#8220;面对接口编程&#8221;的习惯。事实上，我推荐在非常困难得测试才使用。）<br><br>在ASP.NET，我更喜欢使用Model-View-Presenter (MVP)模式，ASP.NET code-behind 页面创建依赖，通过构造函数注入到presenter。另外，我使用用户控件作为模式的View部分，因此ASP.NET code-behind在用户控件（View视图）和他们的Presenter之间，纯粹扮演着MVP&#8220;依赖初始化&#8221;的角色。</p>
<p>另一个实现注入的方式，就是使用应用程式容器&#8230;&#8230;<br><br><strong>DI容器（DI Containers）<br></strong></p>
<p>控制反转（Inversion-of-Control）/依赖注入（Dependency-Injection）容器，无论哪一部分细节的事件触发，都可以监测应用程式、注入依赖。举例，当Customer实例创建时，他可以自动被注入所需要的依赖。首先，这个是非常奇怪的一个概念，但这对于管理大型应用程式多个服务依赖非常有效。不同的容器拥有它们各自的机制，提供管理依赖注入的设置。</p>
<p>Spring .NET允许你使用XML文件定义依赖注入。以下例子，Spring.NET XML使用设置方法注入，为ASPX code-behind page提供数据访问对象的依赖：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">spring</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">context&nbsp;</span><span style="COLOR: #ff0000">type</span><span style="COLOR: #0000ff">="Spring.Context.Support.WebApplicationContext,&nbsp;Spring.Web"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">resource&nbsp;</span><span style="COLOR: #ff0000">uri</span><span style="COLOR: #0000ff">="config://spring/objects"</span><span style="COLOR: #ff0000">&nbsp;</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">context</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">objects&nbsp;</span><span style="COLOR: #ff0000">xmlns</span><span style="COLOR: #0000ff">="http://www.springframework.net"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">&lt;!--</span><span style="COLOR: #008000">&nbsp;Data&nbsp;Access&nbsp;Object&nbsp;that&nbsp;will&nbsp;be&nbsp;injected&nbsp;into&nbsp;ASPX&nbsp;page&nbsp;</span><span style="COLOR: #008000">--&gt;</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">object&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="daoFactory"</span><span style="COLOR: #ff0000">&nbsp;type</span><span style="COLOR: #0000ff">="MyApp.Data.DaoFactory,&nbsp;MyApp.Data"</span><span style="COLOR: #ff0000">&nbsp;</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">object&nbsp;</span><span style="COLOR: #ff0000">type</span><span style="COLOR: #0000ff">="ViewDetails.aspx"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="DaoFactory"</span><span style="COLOR: #ff0000">&nbsp;&nbsp;ref</span><span style="COLOR: #0000ff">="daoFactory"</span><span style="COLOR: #ff0000">&nbsp;</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">object</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">objects</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">spring</span><span style="COLOR: #0000ff">&gt;</span></div>
<p><br>ASPX code-behind 简单地公开一个名为DaoFactory的属性，当页面被呼叫时，来获取所需要的依赖。到Spring .NET's website 可以获取更详细信息和示例。对于Java开发者，肯定参观过Spring's website。</p>
<p>有许多其他的容器，有些根本并不需要很多的XML管理（你有时会看到令你畏惧的500行壮观XML文件）。对于Java开发者，看看<a href="http://www.picocontainer.org/4.1+Container+Comparison">Container Comparison</a>，有很好的对比观点。对于.net开发者，现在的选择比较少（可能是个好事？）。看看一些开源的建议<a href="http://csharp-source.net/open-source/containers">Open Source Inversion of Control Containers in C# </a>。</p>
<p><span style="FONT-SIZE: 18pt; COLOR: #993300"><strong>使用注入Mock对象做单元测试（Unit Testing with Injected Mock Objects）</strong></span><br><br>据经验所得，使用DI最大的好处就是更干净的单元测试和非常好的可插拔性。由于接口，依赖带来了可插拔性。我们来看看DI怎么有利于单元测试。这是一个经常的用例，开发者应对真实数据库编写单元测试。避免让单元测试成为累赘，这需要摒弃以前的慢速单元测试 -- 测试业务逻辑层的时候所依赖的数据访问代码，要不断地访问数据库。Mock对象是实现这个的完美选择。Mock对象模仿真实对象的反应，扮演假设使用真正资源的角色。他们可以很好地模仿访问数据库，模仿访问IO，模仿访问Web Service等等。</p>
<p>下面的代码展示了一个Mock的数据访问，实现了一个贯穿全文的IOrderDao接口。</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;MockOrderDao&nbsp;:&nbsp;IOrderDao&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;Order&nbsp;GetOrderById(</span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000">&nbsp;orderId)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Order&nbsp;foundOrder&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Order();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foundOrder.SaleDate&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">1/1/06</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foundOrder.ID&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;orderId;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;foundOrder;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</span></div>
<br>一个简单的，Mock数据访问对象实现了IOrderDao，因此它能通过构造函数或设置方法注入的方法，传递到各个需要依赖IOrderDao 的对象。现在我们的逻辑层可以脱离访问数据库做测试。在我自己的测试包中，我通常有一段包含真正数据库的测试，然后传入Mock数据库对象以提供业务逻辑对象的单元测试。<br><br><span style="FONT-SIZE: 18pt; COLOR: #993300"><strong>引用文章</strong></span><br><br>
<li><a href="http://www.martinfowler.com/articles/injection.html" target=_blank><u><font color=#0000ff>Inversion of Control Containers and the Dependency Injection Pattern</font></u></a>
<li><a href="http://www-128.ibm.com/developerworks/library/j-mocktest.html" target=_blank><u><font color=#0000ff>Unit testing with mock objects</font></u></a> </li><img src ="http://www.cnitblog.com/seeyeah/aggbug/36861.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/seeyeah/" target="_blank">KiMoGiGi</a> 2007-11-25 21:30 <a href="http://www.cnitblog.com/seeyeah/articles/36861.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[2007-11-19]事件和委托的简单说明</title><link>http://www.cnitblog.com/seeyeah/articles/36521.html</link><dc:creator>KiMoGiGi</dc:creator><author>KiMoGiGi</author><pubDate>Mon, 19 Nov 2007 16:28:00 GMT</pubDate><guid>http://www.cnitblog.com/seeyeah/articles/36521.html</guid><wfw:comment>http://www.cnitblog.com/seeyeah/comments/36521.html</wfw:comment><comments>http://www.cnitblog.com/seeyeah/articles/36521.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/seeyeah/comments/commentRss/36521.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/seeyeah/services/trackbacks/36521.html</trackback:ping><description><![CDATA[原文<br>标题：Events and Delegates simplified<br>作者：Maysam Mahfouzi. <br>链接：<a href="http://www.codeproject.com/csharp/events.asp">http://www.codeproject.com/csharp/events.asp</a><br>翻译完成时间：2007-11-19<br><br>
<hr>
<p><br><span style="FONT-SIZE: 18pt; COLOR: #993300"><strong>内容摘要</strong></span></p>
<ul>
    <li>介绍
    <li>什么是委托
    <li>理解事件
    <li>event 关键字
    <li>最后 </li>
</ul>
<p><span style="FONT-SIZE: 18pt; COLOR: #993300"><strong>介绍【<a name=Introduction1><font style="COLOR: #993300" color=#000000>Introduction</font></a>】</strong></span></p>
当我在学习事件和委托的概念时，我读了大量的文章想去完全地明白它们是怎么使用的；现在，我想在这里把我所有学的东西呈现在此，同时它们大部分也是你需要学习的知识。<br><br>
<p><span style="FONT-SIZE: 18pt; COLOR: #993300"><strong>什么是委托【What are delegates?】</strong></span></p>
<p>委托和时间两个概念是紧密关联的。委托只是一个函数指针（function pointers），也就是说，他们拥有方法（function）的引用。</p>
<p>委托是一个类。当你创建一个实例化时，你要传入一个这个委托所要引用的方法（function）的名称（将作为委托的构造函数的参数）。</p>
<p>每个委托都拥有一个签名（signature），如：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">Delegate&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;SomeDelegate(</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s,&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;b);<br></span></div>
<p><br>是一个委托声明。我说这个委托拥有签名，这个签名的意思就是它表示返回一个int类型和携带2个参数，类型为string和bool。</p>
<p>我说，当你使用委托时，你需要传入一个这个委托所要引用的方法的名称作为它的构造函数参数。重要的一点是，只有拥有相同参数的方法才能作为委托的参数传入。</p>
<p>考虑以下方法：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;SomeFunction(</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;str,&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;bln){<img src="http://www.cnitblog.com/Images/dot.gif">}<br></span></div>
<p>你可以传入这个方法作为SomeDelegate的构造函数，因为他们拥有相同的签名。<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">SomeDelegate&nbsp;sd&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;SomeDelegate(SomeFunction);</span></div>
<p><br>现在，sd 引用了 SomeFunction；换句话说，SomeFunction 被注册到（registered&nbsp; to）sd。如果你调用sd，SomeFunction 将被调用。先记住我所说的&#8220;注册方法&#8221;（registered functions）。后面，我会引用注册方法。<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">sd(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">somestring</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">);</span></div>
<p>&nbsp;</p>
<p>现在你明白了怎么使用委托，让我们继续看看事件。<br><br><span style="FONT-SIZE: 18pt; COLOR: #993300"><strong>理解事件【Understanding Events】</strong></span></p>
<ul>
    <li>Button是一个类，当你点击它的时候，click事件被触发。
    <li>Timer是一个类，每一毫秒，tick事件都被触发。 </li>
</ul>
<p>想知道怎么回事吗？我们通过一个例子学习：</p>
<p>一个假设情节（scenario）：我们有一个名为Counter的类。这个类有一个方法用来计算0到countTo的方法，名为CountTo(int countTo, int reachableNum)；以及每当计算到reachableNum就会引发NumberReached 事件。</p>
<p>我们的类有一个事件：NumberReached。事件是委托类型的变量。如果你需要声明一个事件，你只需要声明一个委托类型变量，并填写event关键字在你的声明处，如下所示：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">&nbsp;NumberReachedEventHandler&nbsp;NumberReached;</span></div>
<p><br>在上面的声明中，NumberReachedEventHandler 只是一个委托。可能这样说比较好：NumberReachedDelegate，但注意，Microsoft 不会说MouseDelegate 或 PaintDelegate，取而代之的是MouseEventHandler 和 PaintEventHandler。那我们就可以方便地说用NumberReachedEventHandler 代替NumberReachedDelegate。好吗？Good！</p>
<p>在我们声明事件之前，我们需要定义我们的委托（我们的事件句柄（event handler））。如下图所示：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">delegate</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;NumberReachedEventHandler(</span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">&nbsp;sender,&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;NumberReachedEventArgs&nbsp;e);</span></div>
<p>就如你看的，我们的委托名称为：NumberReachedEventHandler，并且它的签名包括一个void的返回值和两个参数，参数类型分别为 object 和 NumberReachedEventArgs。如果你想在某处实例化这个委托，那么这个方法必须有相同的签名才能传入作为委托的构造函数参数。</p>
<p>你曾经在你的代码里面用过PaintEventArgs 或 MouseEventArgs ，去判断鼠标的位置，移到哪里，或者判断哪个对象触发了Paint 事件？实际上，我们为客户端提供的数据都继承于EventArgs 类。举例来说，在我们上面的例子，我们要提供一个需要到达的数字，我们就会这样定义类。</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;NumberReachedEventArgs&nbsp;:&nbsp;EventArgs<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;_reached;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;NumberReachedEventArgs(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;num)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">._reached&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;num;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;ReachedNumber<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">get</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;_reached;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br></span></div>
<p>如果你并不需要提供给客户端任何信息，我们可以直接使用EventArgs 。</p>
<p>现在，万事俱备，我们看一看Counter 类：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;Events<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">delegate</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;NumberReachedEventHandler(</span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">&nbsp;sender,&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NumberReachedEventArgs&nbsp;e);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Counter<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">&nbsp;NumberReachedEventHandler&nbsp;NumberReached;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;Counter()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;CountTo(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;countTo,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;reachableNum)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(countTo&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;reachableNum)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;ArgumentException(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">reachableNum&nbsp;should&nbsp;be&nbsp;less&nbsp;than&nbsp;countTo</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;ctr</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;ctr</span><span style="COLOR: #000000">&lt;=</span><span style="COLOR: #000000">countTo;ctr</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(ctr&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;reachableNum)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NumberReachedEventArgs&nbsp;e&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;NumberReachedEventArgs(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reachableNum);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OnNumberReached(e);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">不再计算</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;OnNumberReached(NumberReachedEventArgs&nbsp;e)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(NumberReached&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NumberReached(</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">,&nbsp;e);</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">引发事件</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br></span></div>
<p><br>在以上代码，我们如果计算到达了期望值就会引发事件。这里有几点需要考虑：</p>
<p>&nbsp;1、完成&#8220;触发事件&#8221;是通过呼叫我们的事件（一个名称为NumberReachedEventHandler的委托实例）：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">&nbsp;&nbsp;NumberReached(</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">,&nbsp;e);</span></div>
<p>&nbsp;这样，所有注册方法都会被调用。<br></p>
2、我们通过这样为注册方法提供数据：&nbsp;&nbsp;
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">NumberReachedEventArgs&nbsp;e&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;NumberReachedEventArgs(reachableNum);</span></div>
<p><br>3、提一个问题：为什么我们要通过OnNumberReached(NumberReachedEventArgs e)调用NumberReached(this, e)。为什么部门不直接像下面的代码那样调用。&nbsp;&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(ctr&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;reachableNum)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NumberReachedEventArgs&nbsp;e&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;NumberReachedEventArgs(reachableNum);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">OnNumberReached(e);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">之前的做法</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(NumberReached&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">新做法</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NumberReached(</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">,&nbsp;e);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">引发事件</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">不再计算</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;}<br></span></div>
<p>&nbsp;提得好！如果你想知道为什么我们不直接调用，请再看看OnNumberReached的签名。<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;OnNumberReached(NumberReachedEventArgs&nbsp;e)</span></div>
<ul>
    <li>&nbsp;这个方法是protected的，意味子类也可以使用。
    <li>&nbsp;这个方法是virtual，意味着可以被子类重写。<br>&nbsp;<br>&nbsp;以上两点是很有用的。想象一下，你要设计一个类继承于Counter 。通过重写OnNumberReached 方法，你既可以在引发事件之前，在你要设计的类里面添加一些额外的工作。如： </li>
</ul>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">override</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;OnNumberReached(NumberReachedEventArgs&nbsp;e)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">做额外工作</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">base</span><span style="COLOR: #000000">.OnNumberReached(e);<br>&nbsp;&nbsp;}</span></div>
<p>&nbsp;</p>
<p>&nbsp;注意，如果你没有呼叫base.OnNumberReached(e)，那么事件将永远不会被触发！当你想在子类里面除去它的事件时这样做就非常有用了。有趣的窍门呢，哈哈。</p>
<p>&nbsp;在实际使用中，你可以创建一个新的ASP.NET 网页应用程式，并看看里面生成的后台代码。如你所见，你的page继承自System.Web.UI.Page 类。这个类有一个virtual 和 protected 的方法名为OnInit。你看到在重写的方法中调用InitializeComponent() 做为额外的工作，然后调用基类的 OnInit(e)：<br>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">#region</span><span style="COLOR: #000000">&nbsp;Web&nbsp;Form&nbsp;Designer&nbsp;generated&nbsp;code</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">override</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;OnInit(EventArgs&nbsp;e)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">CODEGEN:&nbsp;This&nbsp;call&nbsp;is&nbsp;required&nbsp;by&nbsp;the&nbsp;ASP.NET&nbsp;Web&nbsp;Form&nbsp;Designer.</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InitializeComponent();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">base</span><span style="COLOR: #000000">.OnInit(e);<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;</span><span style="COLOR: #808080">///</span><span style="COLOR: #008000">&nbsp;</span><span style="COLOR: #808080">&lt;summary&gt;</span><span style="COLOR: #008000"><br>&nbsp;&nbsp;</span><span style="COLOR: #808080">///</span><span style="COLOR: #008000">&nbsp;Required&nbsp;method&nbsp;for&nbsp;Designer&nbsp;support&nbsp;-&nbsp;do&nbsp;not&nbsp;modify<br>&nbsp;&nbsp;</span><span style="COLOR: #808080">///</span><span style="COLOR: #008000">&nbsp;the&nbsp;contents&nbsp;of&nbsp;this&nbsp;method&nbsp;with&nbsp;the&nbsp;code&nbsp;editor.<br>&nbsp;&nbsp;</span><span style="COLOR: #808080">///</span><span style="COLOR: #008000">&nbsp;</span><span style="COLOR: #808080">&lt;/summary&gt;</span><span style="COLOR: #808080"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;InitializeComponent()<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.Load&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;System.EventHandler(</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.Page_Load);<br>&nbsp;&nbsp;}<br>&nbsp;</span><span style="COLOR: #0000ff">#endregion</span></div>
<p>&nbsp;</p>
<p>4、注意，NumberReachedEventHandler 委托定义在类的外面，在命名空间之内，可见于所有类。<br></p>
<p>好的。到时间实践使用一下我们的Counter 类：</p>
<p>在我们示例应用程式中，我们有2个textbox，命名分别为txtCountTo 和 txtReachable ，如图所示<br><img height=168 alt="sample application" src="http://www.codeproject.com/csharp/events/demo.jpg" width=232><br><br>这里就是处理btnRun 的Click事件的代码：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;cmdRun_Click(</span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">&nbsp;sender,&nbsp;System.EventArgs&nbsp;e)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(txtCountTo.Text&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">||</span><span style="COLOR: #000000">&nbsp;txtReachable.Text</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;oCounter&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Counter();<br>&nbsp;&nbsp;&nbsp;&nbsp;oCounter.NumberReached&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;NumberReachedEventHandler(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oCounter_NumberReached);<br>&nbsp;&nbsp;&nbsp;&nbsp;oCounter.CountTo(Convert.ToInt32(txtCountTo.Text),&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert.ToInt32(txtReachable.Text));<br>}<br><br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;oCounter_NumberReached(</span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">&nbsp;sender,&nbsp;NumberReachedEventArgs&nbsp;e)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;MessageBox.Show(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Reached:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;e.ReachedNumber.ToString());<br>}<br><br></span></div>
<p>这个就是初始化事件的语法。</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">oCounter.NumberReached&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;NumberReachedEventHandler(<br>&nbsp;&nbsp;&nbsp;&nbsp;oCounter_NumberReached);</span></div>
<p>现在你明白我们在这里所做的一切了！你刚刚在初始化一个NumberReachedEventHandler 委托（就像你对其他对象一样）。关注一下oCounter_NumberReached 方法签名如之前所提到的要与委托签名相同。</p>
<p>还有，注意我们使用了 += 替代了简单的 = 。</p>
<p>这是因为，委托是一个特殊的对象，他可以持有多于一个的引用（在这里，应该说引用多于一个方法）。距离，如果我们有另外一个与 oCounter_NumberReached 有相同签名的方法oCounter_NumberReached2 ，2个方法同时可以通过以下方法被引用：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">oCounter.NumberReached&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;NumberReachedEventHandler(<br>&nbsp;&nbsp;&nbsp;&nbsp;oCounter_NumberReached);<br>oCounter.NumberReached&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;NumberReachedEventHandler(<br>&nbsp;&nbsp;&nbsp;&nbsp;oCounter_NumberReached2);</span></div>
<p>现在，引发事件之后，两个方法会被依次调用。</p>
<p>如果在我们代码的某处，基于某些原因，我们决定oCounter_NumberReached2 引发NumberReached事件时不需要再调用，我们可以简单地如下这样做：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">oCounter.NumberReached&nbsp;</span><span style="COLOR: #000000">-=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;NumberReachedEventHandler(<br>&nbsp;&nbsp;&nbsp;&nbsp;oCounter_NumberReached2);</span></div>
<p><br><span style="FONT-SIZE: 18pt; COLOR: #993300"><strong>event关键字【event Keyword】</strong></span><br><br>基本上，声明event可以防止delegate设置为null。为什么这个这么重要？想象我现在已经添加一个委托调用列表到我们的类。这样，现在其他客户端可以运行得很好。忽然，有某人简单的使用了&#8220;=&#8221;代替了&#8220;+=&#8221;设置新的回调。这样就会抛弃了所有旧的委托，并且创建一个完全全新的委托到委托调用列表，而这样调用列表中只有它一项而已。这样，当时间到的时候，其他客户就不能收到他们回调函数。这是event 关键字所要解决的一种状况。如果我们在Counter类中移除了event关键，然后尝试编译下面的代码，会出现以下错误：<br><img height=80 src="http://www.codeproject.com/csharp/events/ERROR1.JPG" width=600 border=1><br><br>结论：事件的生命为实例化的委托添加了一层保护。这个保护防止客户端重置委托和它的调用列表，只能允许在调用列表中添加或移除对应目标。[引用<a href="http://weblogs.asp.net/rosherove/archive/2004/03/28/100444.aspx">http://weblogs.asp.net/rosherove/archive/2004/03/28/100444.aspx</a>]<br><br><span style="FONT-SIZE: 18pt; COLOR: #993300"><strong>最后【Finally】</strong></span><br><br>不要忘记在你的应用程式的主构造函数中命名下列代码，代替在cmdRun_Click 事件内定义。我定义他们到cmdRun_Click 事件处理内只是为了方便而已。<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;Form1()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Required&nbsp;for&nbsp;Windows&nbsp;Form&nbsp;Designer&nbsp;support<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;InitializeComponent();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;TODO:&nbsp;Add&nbsp;any&nbsp;constructor&nbsp;code&nbsp;after&nbsp;InitializeComponent&nbsp;call<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;oCounter&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Counter();<br>&nbsp;&nbsp;&nbsp;&nbsp;oCounter.NumberReached&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;NumberReachedEventHandler(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oCounter_NumberReached);<br>&nbsp;&nbsp;&nbsp;&nbsp;oCounter.NumberReached&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;NumberReachedEventHandler(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oCounter_NumberReached2);<br>}<br></span></div>
<p>&nbsp;</p>
<p>文章的源代码在上面提供下载。</p>
<p>如果你投票少于5分的话，请让我知道原因;-)。希望你读完这篇文章后会满意。<br></p><img src ="http://www.cnitblog.com/seeyeah/aggbug/36521.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/seeyeah/" target="_blank">KiMoGiGi</a> 2007-11-20 00:28 <a href="http://www.cnitblog.com/seeyeah/articles/36521.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>