<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type='text/xsl' href='http://prowyh.spaces.live.com/mmm2008-07-24_12.50/rsspretty.aspx?rssquery=en-US;http%3a%2f%2fprowyh.spaces.live.com%2fcategory%2f__x1NET%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%2ffeed.rss' version='1.0'?><rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:msn="http://schemas.microsoft.com/msn/spaces/2005/rss" xmlns:live="http://schemas.microsoft.com/live/spaces/2006/rss" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>prowyh's space: .NET学习笔记</title><description /><link>http://prowyh.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&amp;_c=BlogPart&amp;partqs=cat__x1NET%25E5%25AD%25A6%25E4%25B9%25A0%25E7%25AC%2594%25E8%25AE%25B0</link><language>en-US</language><pubDate>Wed, 03 Sep 2008 02:57:19 GMT</pubDate><lastBuildDate>Wed, 03 Sep 2008 02:57:19 GMT</lastBuildDate><generator>Microsoft Spaces v1.1</generator><docs>http://www.rssboard.org/rss-specification</docs><ttl>60</ttl><cf:parentRSS>http://prowyh.spaces.live.com/blog/feed.rss</cf:parentRSS><live:type>blogcategory</live:type><live:identity><live:id>-1537263819930693984</live:id><live:alias>prowyh</live:alias></live:identity><cf:listinfo><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="typelabel" label="Type" /><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="tag" label="Tag" /><cf:group element="category" label="Category" /><cf:sort element="pubDate" label="Date" data-type="date" default="true" /><cf:sort element="title" label="Title" data-type="string" /><cf:sort ns="http://purl.org/rss/1.0/modules/slash/" element="comments" label="Comments" data-type="number" /></cf:listinfo><item><title>对象引用与托管指针（object references and managed pointers）</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!512.entry</link><description>&lt;div&gt;C/C++中的指针是一种非常灵活而强大的引用机制，但同时也非常脆弱，稍有不慎，就会出错。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Java完全摈弃了指针的概念，而代之以对象引用（object reference），基本上消灭了由指针而导致的错误。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;C#借鉴了Java的作法，引入了对象引用的概念，但同时，不像Java做的那么绝，仍然提供了指针的概念。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;CLR支持三种类型的指针：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;1) 托管指针（managed pointers）&lt;/div&gt;
&lt;div&gt;2) 非托管指针（unmanaged pointers）&lt;/div&gt;
&lt;div&gt;3) 非托管函数指针（unmanaged function pointers）&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;托管指针是一种新类型的指针，指向托管堆中的内存区。&lt;/div&gt;
&lt;div&gt;非托管指针是传统的C/C++指针，指向非托管内存区。&lt;/div&gt;
&lt;div&gt;非托管函数指针也是传统的C/C++指针，指向函数地址。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;C#中的指针属于非托管指针，在C#中不能直接使用托管指针，但作为 by-ref 参数传递机制的 ref 和 out 机制就是利用托管指针实现的。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;C#代码：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;using System;&lt;/div&gt;
&lt;div&gt;public class Test&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;blockquote dir=ltr style="margin-right:0px"&gt;
&lt;div&gt;public static void Main()&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;blockquote dir=ltr style="margin-right:0px"&gt;
&lt;div&gt;int n = 20;&lt;/div&gt;
&lt;div&gt;int m;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;compute(n, out m);&lt;/div&gt;&lt;/blockquote&gt;
&lt;div dir=ltr&gt;}&lt;/div&gt;
&lt;div dir=ltr&gt;private static void compute(int x, out int y)&lt;/div&gt;
&lt;div dir=ltr&gt;{&lt;/div&gt;
&lt;blockquote dir=ltr style="margin-right:0px"&gt;
&lt;div dir=ltr&gt;y = x * 2;&lt;/div&gt;&lt;/blockquote&gt;
&lt;div dir=ltr&gt;}&lt;/div&gt;&lt;/blockquote&gt;
&lt;div dir=ltr&gt;}&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;编译以后，生成如下 IL 代码（为了简单起见，这里只取compute()方法的 IL 代码）：&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;.method private hidebysig static void  compute(int32 x, [out] int32&amp;amp; y) cil managed&lt;br&gt;{&lt;br&gt;  // Code size       7 (0x7)&lt;br&gt;  .maxstack  8&lt;br&gt;  IL_0000:  nop&lt;br&gt;  IL_0001:  ldarg.1&lt;br&gt;  IL_0002:  ldarg.0&lt;br&gt;  IL_0003:  ldc.i4.2&lt;br&gt;  IL_0004:  mul&lt;br&gt;  IL_0005:  stind.i4&lt;br&gt;  IL_0006:  ret&lt;br&gt;} // end of method Test::compute&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;从compute()的 IL 代码即可明显看出，参数 y 的类型即是托管指针 int32&amp;amp;。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;stind.i4 指令将栈顶的 32 位整数值存储到由次栈顶元素（即参数 y）所指示的内存地址中。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;上面的C#代码用的是 out 指示符，如果换成 ref 指示符，生成的 IL 代码是一样的，所不同的是，C#编译器会检查 m 的赋值情况，在执行 compute(n, ref m) 之前，m 必须被明确赋值（definite assigned），而对于 out 指示符，m 不需要赋值。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;托管指针和非托管指针的区别是明显的，托管指针指向的是托管堆中的地址，而非托管指针指向的是非托管内存中的地址。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;那么，对象引用与托管指针又有什么不同呢？&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;从物理实现的角度看，对象引用也是一种指针，而且是一种托管类型的指针。与托管指针不同，对象引用只能指向对象的起始位置，而不能指向对象内部，也就是说，对象引用指向的是对象的整体，而非局部。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;而托管指针一般是指向对象内部某个成员的地址。除此之外，托管指针还可以指向求值栈（evaluation stack）中的位置，或静态变量，甚至非托管内存区。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+%e5%af%b9%e8%b1%a1%e5%bc%95%e7%94%a8%e4%b8%8e%e6%89%98%e7%ae%a1%e6%8c%87%e9%92%88%ef%bc%88object+references+and+managed+pointers%ef%bc%89&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!512.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!512.entry</guid><pubDate>Sun, 20 Jul 2008 17:44:55 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!512/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!512.entry#comment</wfw:comment><dcterms:modified>2008-07-20T17:44:55Z</dcterms:modified></item><item><title>To box or not to box (III)</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!511.entry</link><description>&lt;div&gt;C#代码：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;using System;&lt;/div&gt;
&lt;div&gt;public class Test&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;blockquote dir=ltr style="margin-right:0px"&gt;
&lt;div&gt;public static void Main()&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;blockquote dir=ltr style="margin-right:0px"&gt;
&lt;div&gt;object o = 30;&lt;/div&gt;
&lt;div&gt;int k = (int)o;&lt;/div&gt;&lt;/blockquote&gt;
&lt;div dir=ltr&gt;}&lt;/div&gt;&lt;/blockquote&gt;
&lt;div dir=ltr&gt;}&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;编译以后，生成如下的IL代码：&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;.method public hidebysig static void  Main() cil managed&lt;br&gt;{&lt;br&gt;  .entrypoint&lt;br&gt;  // Code size       17 (0x11)&lt;br&gt;  .maxstack  1&lt;br&gt;  .locals init (object V_0,&lt;br&gt;           int32 V_1)&lt;br&gt;  IL_0000:  nop&lt;br&gt;  IL_0001:  ldc.i4.s   30&lt;br&gt;  IL_0003:  box        [mscorlib]System.Int32&lt;br&gt;  IL_0008:  stloc.0&lt;br&gt;  IL_0009:  ldloc.0&lt;br&gt;  IL_000a:  unbox.any  [mscorlib]System.Int32&lt;br&gt;  IL_000f:  stloc.1&lt;br&gt;  IL_0010:  ret&lt;br&gt;} // end of method Test::Main&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;其中，局部变量 o 成为 V_0，局部变量 k 成为 V_1。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;ldc.i4.s 30 指令我们上文已经见过，将 30 推入栈中。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;box [mscorlib]System.Int32 指令将栈顶元素（30）进行装箱操作，并将对象引用推入栈中。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;stloc.0 指令将栈顶元素（30装箱后的对象引用）存入 V_0。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;ldloc.0 将 V_0 推入栈中。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;unbox 指令有两种形式：unbox valuetype，unbox.any &lt;em&gt;typeTok&lt;/em&gt;。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;unbox valuetype 的意思是将装箱的值类型转换为其原初形式（raw form）&lt;sup&gt;[1]&lt;/sup&gt;，实际上是返回指向对象中的值的指针（valueTypePtr），并推入栈中。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;unbox.any &lt;em&gt;typeTok&lt;/em&gt; 指令抽取对象中的值（也就是被装箱的值），返回，并推入栈中。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;由此可见，指令 unbox 和 unbox.any 是不同的：unbox 只是返回指向值的指针，而 unbox.any 则返回实际的值。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;unbox.any [mscorlib]System.Int32 指令从栈顶元素（对象引用，即 o）所引用的对象中抽取装箱的值（即30），并将其推入栈顶。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;stloc.1 指令将栈顶元素存入 V_1（即 k）。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;由此可见，相比装箱操作（boxing）而言，拆箱操作（unboxing）只是取对象中的地址或抽取对象中的值，并不算太费时。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;[1] 值类型有两种表示：&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;1) 原初形式（raw form） ，当某个值类型嵌入其它对象中时，即以原初形式表示；&lt;/div&gt;
&lt;div dir=ltr&gt;2) 装箱形式（boxed form），当某个值类型的数值（data）被装箱到一个对象中时，即以装箱形式表示，此时可以作为一个独立的实体（an independent entity）而存在。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+To+box+or+not+to+box+(III)&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!511.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!511.entry</guid><pubDate>Sat, 19 Jul 2008 16:10:51 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!511/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!511.entry#comment</wfw:comment><dcterms:modified>2008-07-19T16:25:38Z</dcterms:modified></item><item><title>To box or not to box (II)</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!510.entry</link><description>&lt;div&gt;C#代码：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;using System;&lt;/div&gt;
&lt;div&gt;public class Test&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;blockquote dir=ltr style="margin-right:0px"&gt;
&lt;div&gt;public static void Main()&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;blockquote dir=ltr style="margin-right:0px"&gt;
&lt;div&gt;int n = 30;&lt;/div&gt;
&lt;div&gt;Console.Write(&amp;quot;n: {0}&amp;quot;, n);&lt;/div&gt;&lt;/blockquote&gt;
&lt;div dir=ltr&gt;}&lt;/div&gt;&lt;/blockquote&gt;
&lt;div dir=ltr&gt;}&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;编译以后，将生成如下的IL代码：&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;.method public hidebysig static void  Main() cil managed&lt;br&gt;{&lt;br&gt;  .entrypoint&lt;br&gt;  // Code size       22 (0x16)&lt;br&gt;  .maxstack  2&lt;br&gt;  .locals init (int32 V_0)&lt;br&gt;  IL_0000:  nop&lt;br&gt;  IL_0001:  ldc.i4.s   30&lt;br&gt;  IL_0003:  stloc.0&lt;br&gt;  IL_0004:  ldstr      &amp;quot;n: {0}&amp;quot;&lt;br&gt;  IL_0009:  ldloc.0&lt;br&gt;  IL_000a:  box        [mscorlib]System.Int32&lt;br&gt;  IL_000f:  call       void [mscorlib]System.Console::WriteLine(string, object)&lt;br&gt;  IL_0014:  nop&lt;br&gt;  IL_0015:  ret&lt;br&gt;} // end of method Test::Main&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;ldc.i4.s &lt;em&gt;num&lt;/em&gt; 的意思是 push &lt;em&gt;num&lt;/em&gt; onto the stack as int32, short form. 所以 ldc.i4.s 30 的意思是将 30 作为 32 位整数推入栈顶。&lt;/div&gt;
&lt;div dir=ltr&gt;stloc.0 的意思是 pop a value from stack into local variable 0.&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;所以 ldc.i4.s 30 和 stloc.0 两条指令执行的结果是完成C#中的赋值（变量定义）语句：&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;int n = 30;&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;这里，局部变量 n 变成了 V_0。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;ldstr &amp;quot;n: {0}&amp;quot; 指令的意思是将字符串 &amp;quot;n: {0}&amp;quot; 推入栈顶。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;ldloc.0 的意思是 load local variable 0 onto stack，即将 V_0 的值推入栈顶。（此时由ldstr推入的字符串成为次栈顶元素。）&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;box &lt;em&gt;typeTok&lt;/em&gt; 的意思是 convert a boxable value to its boxed form，即将值转换为装箱形式，即引用类型。&lt;/div&gt;
&lt;div dir=ltr&gt;box [mscorlib]System.Int32 即是将栈顶的 32 位整数值转换为装箱后的形式，然后返回对象引用，并将此对象引用推入栈顶。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;call void [mscorlib]System.Console::WriteLine(string, object) 即是以栈顶元素（装箱后的对象引用）和次栈顶元素（由ldstr推入的字符串）为参数，调用WriteLine方法。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;这段代码唯一不好理解的是由 box 完成的装箱操作。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;简单说来，box 操作分为三步：&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;1) 创建一个无名的新对象，类似于 new Object()；&lt;/div&gt;
&lt;div dir=ltr&gt;2) 将要装箱的值（存在于栈顶）从栈顶弹出，拷贝到新创建的对象中；&lt;/div&gt;
&lt;div dir=ltr&gt;3) 返回该对象引用，并推入栈顶。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;如果转换为C的语义，可以这样理解：&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;1) 调用malloc()分配适当大小的内存区；&lt;/div&gt;
&lt;div dir=ltr&gt;2) 将值从栈中弹出，拷贝到该内存区；&lt;/div&gt;
&lt;div dir=ltr&gt;3) 返回该内存区的地址，并推入栈顶。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;当然，这只是一个有助于理解的类比，实际的实现并不一定与此相同。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;由 box 指令的操作可以看出，存在两个比较费时的操作，即1) 创建新对象，以及2) 值的拷贝。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;由此可见，虽然C#通过 boxing 机制模糊了引用类型和值类型的边界，使得程序员可以写出一致的代码，但 box 操作不可避免地存在着性能损失。所以，应该尽可能地避免 box 操作。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+To+box+or+not+to+box+(II)&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!510.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!510.entry</guid><pubDate>Sat, 19 Jul 2008 13:45:42 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!510/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!510.entry#comment</wfw:comment><dcterms:modified>2008-07-19T15:22:06Z</dcterms:modified></item><item><title>To box or not to box</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!507.entry</link><description>&lt;div&gt;给定：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;int n = 30;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;下面的两条C#语句有什么区别吗？&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;1. System.Console.WriteLine(&amp;quot;n: {0}&amp;quot;, n);&lt;/div&gt;
&lt;div&gt;2. System.Console.WriteLine(&amp;quot;n: {0}&amp;quot;, n.ToString());&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;当然，这两条语句产生的结果是没有任何区别的：&lt;/div&gt;
&lt;div&gt;n: 30&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;既然如此，还有什么可研究的吗？先别急着下结论，研究研究再说。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;首先，我们来看看WriteLine()的语法格式：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;public static void WriteLine(string format, Object arg0)&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;从此语法格式可知，WriteLine()的第二个参数要求是Object类型，上述的语句2是满足的，因为n.ToString()的结果是string类型，而string类型就是Object类型；而语句1是不满足的，因为n是值类型（value type），而WriteLine()又没有形如WriteLine(string format, int arg0)的语法，既然如此，那 n 又是如何转换为 Object 类型的呢？（否则编译就会出错：类型不匹配！）&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;C#区分了引用类型（reference type）和值类型（value type）。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;引用类型涉及到两个实体（当然，对程序员是透明的）：对象和对象引用，对象存在于堆（heap）中，而对象引用存在于栈（stack）中。对于一个对象，可以存在若干个对象引用指向该对象；当然也存在不指向任何对象的对象引用，该对象引用的值即为null；对于不存在任何对象引用的对象，即成为GC要回收的对象。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;而对于值类型，只存在一个实体，即值本身，该实体存在于栈中。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;由此可见，引用类型和值类型有着很大的区别。这种区别有时候是必要的，如：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;for (int i = 0; i &amp;lt; 10; i++)&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;blockquote dir=ltr style="margin-right:0px"&gt;
&lt;div&gt;// loop statements&lt;/div&gt;&lt;/blockquote&gt;
&lt;div dir=ltr&gt;}&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;这里的循环控制变量 i 作为值类型，就非常自然而高效。如果 i 也作为引用类型，将大大降低 for 语句的效率。但有的时候却是不必要的，如上述的WriteLine()语句，如果引用类型和值类型不能互相转换，则必须要有类似如下的WriteLine语法：&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;public static void WriteLine(string format, int arg0)&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;而且WriteLine对于所有的值类型都要有类似的语法，这将使得 FCL 非常庞大而笨拙！&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;C#语言通过 box/unbox 设施（机制）比较好地解决了这个问题。使得下述声明&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;public static void WriteLine(string format, Object arg0)&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;适用于所有的数据类型。所以，我们可以写出像&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;WriteLine(&amp;quot;n: {0}&amp;quot;, n);&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;这样的语句。这里的 n 通过 box 机制自动转换为 Object 类型。通过检查编译器生成的中间代码可以更清楚地看出这一点：&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;  .locals init (int32 V_0)&lt;br&gt;  IL_0000:  nop&lt;br&gt;  IL_0001:  ldc.i4.s   30&lt;br&gt;  IL_0003:  stloc.0&lt;br&gt;  IL_0004:  ldstr      &amp;quot;n: {0}&amp;quot;&lt;br&gt;  IL_0009:  ldloc.0&lt;br&gt;  IL_000a:  box      [mscorlib]System.Int32&lt;br&gt;  IL_000f:   call      void [mscorlib]System.Console::WriteLine(string, object)&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;从这段 IL 代码中可以看出，n 通过 box 指令转换为了引用类型，然后再调用WriteLine(string, object)方法。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;
&lt;div dir=ltr&gt;从这个例子可以看出，C#中的 box/unbox 机制，就像 using 语句（using statement，非using directive）一样，是一种便用设施（handy facility）。这种便用设施使得程序更加优雅，正因为此，Java语言从5.0开始也引入了 box/unbox 机制。&lt;/div&gt;
&lt;div dir=ltr&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+To+box+or+not+to+box&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!507.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!507.entry</guid><pubDate>Mon, 14 Jul 2008 18:46:38 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!507/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!507.entry#comment</wfw:comment><dcterms:modified>2008-07-19T12:46:23Z</dcterms:modified></item><item><title>C# and .NET</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!482.entry</link><description>&lt;div&gt;The programming language of choice for .NET is C#, which builds on the lessons learned from C (high performance), C++ (object-oriented structure), Java™ (garbage collection, high security), and Visual Basic (rapid development) to create a language ideally suited for developing component-based, n-tier, distributed Windows client and web applications.&lt;/div&gt;
&lt;div&gt;&lt;br&gt;C# 3.0 brings greatly enhanced features and a powerful new development environment. It is the crowning achievement of Microsoft’s R&amp;amp;D investment. It is wicked cool.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div align=right&gt;&lt;em&gt;-- Programming C# 3.0 by Jesse Liberty and Donald Xie&lt;/em&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+C%23+and+.NET&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!482.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!482.entry</guid><pubDate>Sat, 29 Mar 2008 15:12:47 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!482/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!482.entry#comment</wfw:comment><dcterms:modified>2008-03-29T15:16:32Z</dcterms:modified></item><item><title>ExecuteNonQuery的问题</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!464.entry</link><description>&lt;div&gt;MSDN对ExecuteNonQuery()的描述：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Executes a Transact-SQL statement against the connection and returns the number of rows affected. &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;想当然地，我们会认为如果ExecuteNonQuery()所执行的SQL语句影响多行的话，就返回影响的行数，而如果不影响的话，就应该回返0。例如，对于如下的SQL语句：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;IF NOT EXISTS(SELECT * FROM tbl WHERE &amp;lt;condition&amp;gt;)&lt;/div&gt;
&lt;div&gt;BEGIN&lt;/div&gt;
&lt;div&gt;    INSERT INTO tbl (...) VALUES (...)&lt;/div&gt;
&lt;div&gt;END&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;如果IF条件满足，则执行INSERT，此时影响1行，ExecuteNonQuery应该返回1，而如果IF条件不满足，则不影响，此时ExecuteNonQuery应该返回0。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;而事实是：如果IF条件不满足，ExecuteNonQuery返回-1！令人匪夷所思！另外，&lt;a href="http://jstawski.com/archive/2006/10/04/ExecuteNonQuery-Always-Returns-_2D00_1.aspx" target="_blank"&gt;如果ExecuteNonQuery所执行的存储过程中使用了SET NOCOUNT ON/SET NOCOUNT OFF，ExecuteNonQuery也返回-1&lt;/a&gt;！&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;所以，不能相信Microsoft对API的描述，必须一一试过。My God!&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+ExecuteNonQuery%e7%9a%84%e9%97%ae%e9%a2%98&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!464.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!464.entry</guid><pubDate>Wed, 09 Jan 2008 03:42:33 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!464/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!464.entry#comment</wfw:comment><dcterms:modified>2008-01-09T03:43:26Z</dcterms:modified></item><item><title>Visual Studio .NET Debugger的一个问题及其解决</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!463.entry</link><description>&lt;div&gt;实际上，这本来不算一个问题，但如果不知道原因及解决办法的话，就足以让人frustrated。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;在Visual Studio .NET 2005中新建一个ASP.NET项目，假设使用默认站点，即&lt;a href="http://localhost/"&gt;http://localhost&lt;/a&gt;，则Visual Studio .NET自动在根目录下生成两个初始文件：Default.aspx及Default.aspx.cs。此时，按F5进行调试运行，则弹出如下对话框：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;img src="http://mystuff.ask.com/servlet/snipit_image_proxy?uid=b6c75159f83fb178253c52eafa14db41&amp;amp;img_guid=29e44bc3ca5ec7688fd88d1d733ff90f&amp;amp;locale=en_US"&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;弹出此对话框的原因是因为ASP.NET项目的根目录下没有Web.config文件，从而没有启用调试功能造成的，解决办法是打开IIS管理器，编辑ASP.NET配置，如下图所示：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;img src="http://mystuff.ask.com/servlet/snipit_image_proxy?uid=b6c75159f83fb178253c52eafa14db41&amp;amp;img_guid=8fc31d77955ed3b83bde8bb8168037e9&amp;amp;locale=en_US"&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;或手工编辑Web.config文件：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;/div&gt;
&lt;div&gt;&amp;lt;configuration&amp;gt;&lt;/div&gt;
&lt;div&gt;    &amp;lt;system.web&amp;gt;&lt;/div&gt;
&lt;div&gt;        &amp;lt;compilation debug=&amp;quot;true&amp;quot; /&amp;gt;&lt;/div&gt;
&lt;div&gt;    &amp;lt;/system.web&amp;gt;&lt;/div&gt;
&lt;div&gt;&amp;lt;/configuration&amp;gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;这个最小的Web.config文件启用了Debug功能，就可以避免上面的问题。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;但这并不是本文所要讲述的问题（虽然也是一个问题）。解决了这个小问题之后，更大的问题是下面的对话框：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;img src="http://mystuff.ask.com/servlet/snipit_image_proxy?uid=b6c75159f83fb178253c52eafa14db41&amp;amp;img_guid=43bf844412f4c06d41366d0bfb5050db&amp;amp;locale=en_US"&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Google了一下，发现这是一个普遍问题，后来在Visual Studio .NET的帮助文件中找到了解决办法：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;img src="http://mystuff.ask.com/servlet/snipit_image_proxy?uid=b6c75159f83fb178253c52eafa14db41&amp;amp;img_guid=ba0535b9c2fcd653fbca5744887240bb&amp;amp;locale=en_US"&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;如图中红线标记所示，启用“集成Windows身份验证”即可。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;但为什么需要启用“集成Windows身份验证”呢？后来在Microsoft的&lt;a href="http://support.microsoft.com/kb/937523" target="_blank"&gt;KB 937523&lt;/a&gt;中找到了这样一段话：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;When the client tries to automatically attach the debugger in an ASP.NET 2.0 application, the client sends a HTTP request that contains the DEBUG verb. This HTTP request is used to verify that the process of the application is running and to select the correct process to attach. This HTTP request must be authenticated by using Windows Authentication.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;最后在&lt;a href="http://blogs.msdn.com/mkpark/articles/86872.aspx" target="_blank"&gt;Min Kwan Park's bLog&lt;/a&gt;中发现有如此多与Visual Studio Debugger有关的问题，基本都是Unable to start debugging on the web server。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+Visual+Studio+.NET+Debugger%e7%9a%84%e4%b8%80%e4%b8%aa%e9%97%ae%e9%a2%98%e5%8f%8a%e5%85%b6%e8%a7%a3%e5%86%b3&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!463.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!463.entry</guid><pubDate>Thu, 27 Dec 2007 21:20:18 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!463/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!463.entry#comment</wfw:comment><dcterms:modified>2007-12-27T21:21:37Z</dcterms:modified></item><item><title>Hosting WebBrowser：一个令人沮丧的问题</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!461.entry</link><description>&lt;div&gt;一个简单的在Windows Form中嵌入WebBrowser control的应用：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;axWebBrowser.DocumentComplete += new AxSHDocVw.DWebBrowserEvents2_DocumentCompleteEventHandler(this.axWebBrowser_DocumentComplete);&lt;br&gt;object o = null;&lt;br&gt;axWebBrowser.Navigate2(ref __url, ref o, ref o, ref o, ref o);&lt;/div&gt;
&lt;div&gt;// ...........&lt;/div&gt;
&lt;div&gt;
&lt;p align=left&gt;private void axWebBrowser_DocumentComplete(object sender, AxSHDocVw.DWebBrowserEvents2_DocumentCompleteEvent e)&lt;br&gt;{&lt;br&gt;    MessageBox.Show(&amp;quot;Document Completed&amp;quot;);&lt;br&gt;    IHTMLDocument2 doc = (IHTMLDocument2)axWebBrowser.Document;&lt;br&gt;    // ........&lt;br&gt;}
&lt;p align=left&gt;在开发机器上运行正常，在其它（测试）机器上，axWebBrowser_DocumentComplete()不执行！
&lt;p align=left&gt;google一下，发现很多人在hosting WebBrowser control时遇到问题，问题各种各样，说明在.NET中与IE这样复杂的COM component进行interop，实在不是一件easy的活儿！
&lt;p align=left&gt;在与这个问题fighting了两天之后，game终于over了！
&lt;p align=left&gt;IHTMLDocument2的wrapper在Microsoft.mshtml.dll中，而测试机器虽然安装了.NET Framework，但Global Assembly Cache中仍然没有这个程序集，在运行无法加载。下载一份Microsoft.mshtml.dll放入程序所在目录，则一切OK！
&lt;p align=left&gt;两点疑惑：
&lt;p align=left&gt;1、虽然由于无法加载Microsoft.mshtml.dll而导致IHTMLDocument2失败，但前面的MessageBox.Show()也不执行！
&lt;p align=left&gt;2、既然安装了.NET Framework，GAC中为什么没有Microsoft.mshtml.dll呢？如果Microsoft.mshtml.dll是在SDK（VS 2005）中，那为什么VS不生成redistributed assembly呢？
&lt;p align=left&gt;有消息说，Microsoft有一支200人的团队在从事IE 8的开发，IE这个玩意儿，和Windows一样，越搞越复杂，越搞越慢。
&lt;p align=left&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+Hosting+WebBrowser%ef%bc%9a%e4%b8%80%e4%b8%aa%e4%bb%a4%e4%ba%ba%e6%b2%ae%e4%b8%a7%e7%9a%84%e9%97%ae%e9%a2%98&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!461.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!461.entry</guid><pubDate>Wed, 05 Dec 2007 18:30:23 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!461/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!461.entry#comment</wfw:comment><dcterms:modified>2007-12-05T18:30:23Z</dcterms:modified></item><item><title>IEnumerable &amp; IEnumerator</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!460.entry</link><description>&lt;div&gt;public interface IEnumerable&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;    IEnumerator GetEnumerator();&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;public interface IEnumerator&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;    bool MoveNext();&lt;/div&gt;
&lt;div&gt;    void Reset();&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;    Object Current { get; }&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;IEnumerable和IEnumerator有什么区别？这是一个很让人困惑的问题（在很多forum里都看到有人在问这个问题）。研究了半天，得到以下几点认识：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;1、一个Collection要支持foreach方式的遍历，必须实现IEnumerable接口（亦即，必须以某种方式返回IEnumerator object）。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;2、IEnumerator object具体实现了iterator（通过MoveNext()，Reset()，Current）。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;3、从这两个接口的用词选择上，也可以看出其不同：IEnumerable是一个声明式的接口，声明实现该接口的class是“可枚举（enumerable）”的，但并没有说明如何实现枚举器（iterator）；IEnumerator是一个实现式的接口，IEnumerator object就是一个iterator。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;4、IEnumerable和IEnumerator通过IEnumerable的GetEnumerator()方法建立了连接，client可以通过IEnumerable的GetEnumerator()得到IEnumerator object，在这个意义上，将GetEnumerator()看作IEnumerator object的factory method也未尝不可。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+IEnumerable+%26+IEnumerator&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!460.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!460.entry</guid><pubDate>Mon, 26 Nov 2007 22:39:06 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!460/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!460.entry#comment</wfw:comment><dcterms:modified>2007-12-03T09:55:05Z</dcterms:modified></item><item><title>Collection &amp; Iterator in .NET</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!459.entry</link><description>&lt;div&gt;在OOP术语中，Collection是指包含其它对象的一种数据结构。C++ STL泛称为Container，.NET Framework泛称为Collection。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Iterator是一种遍历Collection的机制：an iterator is an object which allows a programmer to traverse through all the elements of a collection, regardless of its specific implementation.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Collection提供了聚集对象的容器（Container），Iterator提供了访问容器中对象的统一方法，Collection与Iterator两者结合，为开发人员提供了表示、操纵各种复杂数据结构的强大工具。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;例一：Collection与Iterator在C# 1.0中的实现&lt;/div&gt;
&lt;p&gt;using System;&lt;br&gt;using System.Collections;&lt;br&gt;&lt;br&gt;namespace Levensoft&lt;br&gt;{&lt;br&gt;    // data object contained in PeopleCollection&lt;br&gt;    public class Person&lt;br&gt;    {&lt;br&gt;        public Person(string name, int age)&lt;br&gt;        {&lt;br&gt;            this.name = name;&lt;br&gt;            this.age = age;&lt;br&gt;        }&lt;br&gt;        &lt;br&gt;        public string Name&lt;br&gt;        {&lt;br&gt;            get { return name; }&lt;br&gt;        }&lt;br&gt;        public int Age&lt;br&gt;        {&lt;br&gt;            get { return age; }&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        private string name;&lt;br&gt;        private int age;&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    public class PeopleCollection : IEnumerable&lt;br&gt;    {&lt;br&gt;        // IEnumerable&lt;br&gt;        public IEnumerator GetEnumerator()&lt;br&gt;        {&lt;br&gt;            return new PeopleCollectionEnum(_peopleCollection);&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        // IEnumerator&lt;br&gt;        private class PeopleCollectionEnum : IEnumerator&lt;br&gt;        {&lt;br&gt;            private Person[] _peopleCollection;&lt;br&gt;            private int _position = -1;&lt;br&gt;&lt;br&gt;            public PeopleCollectionEnum(Person[] list)&lt;br&gt;            {&lt;br&gt;                _peopleCollection = list;&lt;br&gt;            }&lt;br&gt;&lt;br&gt;            public bool MoveNext()&lt;br&gt;            {&lt;br&gt;                _position++;&lt;br&gt;&lt;br&gt;                return (_position &amp;lt; _peopleCollection.Length);&lt;br&gt;            }&lt;br&gt;            public void Reset()&lt;br&gt;            {&lt;br&gt;                _position = -1;&lt;br&gt;            }&lt;br&gt;            public object Current&lt;br&gt;            {&lt;br&gt;                get&lt;br&gt;                {&lt;br&gt;                    try&lt;br&gt;                    {&lt;br&gt;                        return _peopleCollection[_position];&lt;br&gt;                    }&lt;br&gt;                    catch (IndexOutOfRangeException)&lt;br&gt;                    {&lt;br&gt;                        throw new InvalidOperationException();&lt;br&gt;                    }&lt;br&gt;                }&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        public PeopleCollection()&lt;br&gt;        {&lt;br&gt;            _peopleCollection = new Person[3]&lt;br&gt;            {&lt;br&gt;                new Person(&amp;quot;Bob&amp;quot;, 30),&lt;br&gt;                new Person(&amp;quot;Jim&amp;quot;, 31),&lt;br&gt;                new Person(&amp;quot;Sue&amp;quot;, 29),&lt;br&gt;            };&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        // Indexer &amp;amp; Length provide the ability of Array-like accessor&lt;br&gt;        public Person this[int index]&lt;br&gt;        {&lt;br&gt;            get&lt;br&gt;            {&lt;br&gt;                try&lt;br&gt;                {&lt;br&gt;                    return _peopleCollection[index];&lt;br&gt;                }&lt;br&gt;                catch (IndexOutOfRangeException) { throw; }&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        public int Length&lt;br&gt;        {&lt;br&gt;            get&lt;br&gt;            {&lt;br&gt;                return _peopleCollection.Length;&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        private Person[] _peopleCollection;&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    public class test&lt;br&gt;    {&lt;br&gt;        public static void Main()&lt;br&gt;        {&lt;br&gt;            PeopleCollection peopleCollection = new PeopleCollection();&lt;br&gt;&lt;br&gt;            // IEnumerable &amp;amp; IEnumerator enable &lt;em&gt;foreach statement&lt;/em&gt;&lt;br&gt;            foreach (Person p in peopleCollection)&lt;br&gt;            {&lt;br&gt;                Console.WriteLine(p.Name + &amp;quot;\t\t&amp;quot; + p.Age);&lt;br&gt;            }&lt;br&gt;&lt;br&gt;            // Indexer &amp;amp; Length enable &lt;em&gt;for statement&lt;/em&gt;&lt;br&gt;            for (int i = 0; i &amp;lt; peopleCollection.Length; i++)&lt;br&gt;            {&lt;br&gt;                Console.WriteLine(peopleCollection[i].Name + &amp;quot;\t\t&amp;quot; + peopleCollection[i].Age);&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;}
&lt;p&gt;例二：Collection &amp;amp; Iterator在C# 2.0中的实现
&lt;p&gt;using System;&lt;br&gt;using System.Collections;&lt;br&gt;&lt;br&gt;namespace Levensoft&lt;br&gt;{&lt;br&gt;    public class Person&lt;br&gt;    {&lt;br&gt;        public Person(string name, int age)&lt;br&gt;        {&lt;br&gt;            this.name = name;&lt;br&gt;            this.age = age;&lt;br&gt;        }&lt;br&gt;        &lt;br&gt;        public string Name&lt;br&gt;        {&lt;br&gt;            get { return name; }&lt;br&gt;        }&lt;br&gt;        public int Age&lt;br&gt;        {&lt;br&gt;            get { return age; }&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        private string name;&lt;br&gt;        private int age;&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    public class PeopleCollection : IEnumerable&lt;br&gt;    {&lt;br&gt;        public IEnumerator GetEnumerator()&lt;br&gt;        {&lt;br&gt;            // iterator block&lt;br&gt;            for (int i = 0; i &amp;lt; _peopleCollection.Length; i++)&lt;br&gt;            {&lt;br&gt;                yield return _peopleCollection[i];&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        public PeopleCollection()&lt;br&gt;        {&lt;br&gt;            _peopleCollection = new Person[3]&lt;br&gt;            {&lt;br&gt;                new Person(&amp;quot;Bob&amp;quot;, 30),&lt;br&gt;                new Person(&amp;quot;Jim&amp;quot;, 31),&lt;br&gt;                new Person(&amp;quot;Sue&amp;quot;, 29),&lt;br&gt;            };&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        public Person this[int index]&lt;br&gt;        {&lt;br&gt;            get&lt;br&gt;            {&lt;br&gt;                try&lt;br&gt;                {&lt;br&gt;                    return _peopleCollection[index];&lt;br&gt;                }&lt;br&gt;                catch (IndexOutOfRangeException) { throw; }&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        public int Length&lt;br&gt;        {&lt;br&gt;            get&lt;br&gt;            {&lt;br&gt;                return _peopleCollection.Length;&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        private Person[] _peopleCollection;&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    public class test&lt;br&gt;    {&lt;br&gt;        public static void Main()&lt;br&gt;        {&lt;br&gt;            PeopleCollection peopleCollection = new PeopleCollection();&lt;br&gt;&lt;br&gt;            foreach (Person p in peopleCollection)&lt;br&gt;            {&lt;br&gt;                Console.WriteLine(p.Name + &amp;quot;\t\t&amp;quot; + p.Age);&lt;br&gt;            }&lt;br&gt;&lt;br&gt;            for (int i = 0; i &amp;lt; peopleCollection.Length; i++)&lt;br&gt;            {&lt;br&gt;                Console.WriteLine(peopleCollection[i].Name + &amp;quot;\t\t&amp;quot; + peopleCollection[i].Age);&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;}
&lt;p&gt;从例二可以看出，C# 2.0通过iterator block大大简化了Collection的遍历机制（iterator）。实际上，iterator block是C# 2.0为程序员提供的一种便利设施（handy facility），C#编译器在编译时，仍然生成如例一所示的enumerator class。
&lt;p&gt; &lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+Collection+%26+Iterator+in+.NET&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!459.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!459.entry</guid><pubDate>Mon, 26 Nov 2007 22:13:04 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!459/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!459.entry#comment</wfw:comment><dcterms:modified>2007-11-26T22:13:04Z</dcterms:modified></item><item><title>Thread &amp; Thread ApartmentState</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!458.entry</link><description>&lt;div&gt;Apartment是COM的概念，在.NET中本不涉及Apartment，但如果需要与COM互操作（COM Interop），则需要适当设置.NET线程的ApartmentState。&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;1、Attribute设置只适用于入口点方法（entry method）如Main()，对其它方法无意义；&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;2、获取ApartmentState使用GetApartmentState()，设置ApartmentState使用SetApartmentState(ApartmentState.Enum)。&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;示例如下：&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;using System;&lt;br&gt;using System.Threading;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;namespace Levensoft&lt;br&gt;{&lt;br&gt;    public class ThreadApartmentState&lt;br&gt;    {&lt;br&gt;        public static void Main()&lt;br&gt;        {&lt;br&gt;            Thread t = new Thread(new ThreadStart(ThreadTest));&lt;br&gt;            Console.WriteLine(&amp;quot;t.ApartmentState: &amp;quot; + t.GetApartmentState().ToString());&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;            t.SetApartmentState(ApartmentState.STA);&lt;br&gt;            Console.WriteLine(&amp;quot;t.ApartmentState: &amp;quot; + t.GetApartmentState().ToString());&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;            t.Start();&lt;br&gt;        }&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;        public static void ThreadTest()&lt;br&gt;        {&lt;br&gt;            Thread tt = Thread.CurrentThread;&lt;br&gt;            Console.WriteLine(&amp;quot;tt.ApartmentState: &amp;quot; + tt.GetApartmentState().ToString());&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;}&lt;/div&gt;
&lt;div&gt;&lt;br&gt;此例的输出：&lt;/div&gt;
&lt;div&gt;t.ApartmentState: Unkown&lt;/div&gt;
&lt;div&gt;t.ApartmentState: STA&lt;/div&gt;
&lt;div&gt;tt.ApartmentState: STA&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;通过此例归纳出的简单结论：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;1、通过new Thread()创建的线程，初始ApartmentState为Unkown；&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;2、可以通过SetApartmentState()设置线程的ApartmentState为STA或MTA；&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;3、线程的ApartmentState只可以设置一次，而且是在调用Start()启动线程之前设置。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;4、线程的ApartmentState只能在其创建者中设置，而不能在线程本身的代码中设置，因为线程代码的执行是由Start()启动的。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+Thread+%26+Thread+ApartmentState&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!458.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!458.entry</guid><pubDate>Mon, 26 Nov 2007 09:50:47 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!458/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!458.entry#comment</wfw:comment><dcterms:modified>2007-11-26T09:53:06Z</dcterms:modified></item><item><title>.NET Configuration</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!457.entry</link><description>&lt;div&gt;.NET Configuration对于系统及应用程序的运行环境配置提供了极大的灵活性，但由于版本的关系，配置信息的表述和读取显得相当混乱，许多文章甚至书籍中给出的示例代码都不能在.NET 2.0下运行，下面给出一个可以运行的例子。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;1、config文件片断&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&amp;lt;configuration&amp;gt;&lt;/div&gt;
&lt;div&gt;    &amp;lt;appSettings&amp;gt;&lt;/div&gt;
&lt;div&gt;        &amp;lt;add key=&amp;quot;logfile&amp;quot; value=&amp;quot;C:\logfile\event.log&amp;quot; /&amp;gt;&lt;/div&gt;
&lt;div&gt;    &amp;lt;/appSettings&amp;gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;    &amp;lt;connectionStrings&amp;gt;&lt;/div&gt;
&lt;div&gt;        &amp;lt;add name=&amp;quot;myConnString&amp;quot;&lt;/div&gt;
&lt;div&gt;                 providerName=&amp;quot;System.Data.SqlClient&amp;quot;&lt;/div&gt;
&lt;div&gt;                 connectionString=&amp;quot;Server=(local);Database=mydb;uid=sa;pwd=mypass&amp;quot; /&amp;gt;&lt;/div&gt;
&lt;div&gt;    &amp;lt;/connectionStrings&amp;gt;&lt;/div&gt;
&lt;div&gt;&amp;lt;/configuration&amp;gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;此config文件片断定义了两项内容：一是logfile文件名，二是数据库连接字符串。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;对于Web Forms应用，将此文件命名为web.config并存于网站的根目录下。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;对于Windows Forms应用，将此文件命名为&lt;em&gt;app&lt;/em&gt;.config并存于应用程序的根目录下。如程序名为wordpad.exe，则config文件为wordpad.exe.config，且与wordpad.exe位于同一目录下。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;2、Web Forms应用中对配置信息的读取&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;下面的代码读入上述config文件中定义的内容：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;// open config file&lt;/div&gt;
&lt;div&gt;Configuration config = WebConfigurationManager.OpenWebConfiguration(&amp;quot;/&amp;quot;);&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;// get logfile&lt;/div&gt;
&lt;div&gt;AppSettingsSection appSettings = config.AppSettings as AppSettingsSection;&lt;/div&gt;
&lt;div&gt;string logfile = appSettings.Settings[&amp;quot;logfile&amp;quot;].Value;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;// get connectionString&lt;/div&gt;
&lt;div&gt;ConnectionStringsSection cnstrSection = config.ConnectionStrings;&lt;/div&gt;
&lt;div&gt;ConnectionStringSettingsCollection cnstrCollection = cnstrSection.ConnectionStrings;&lt;/div&gt;
&lt;div&gt;ConnectionStringSettings cnstrSettings = cnstrCollection[&amp;quot;myConnString&amp;quot;];&lt;/div&gt;
&lt;div&gt;string connectionString = cnstrSettings.ConnectionString;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;3、Windows Forms应用中对配置信息的读取&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Windows Forms读取config文件的代码，除了打开文件的代码不同之外，其余与Web Forms中的读取代码是一样的。下面给出一种简化的读取代码：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;// open config file&lt;/div&gt;
&lt;div&gt;Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;// get logfile&lt;/div&gt;
&lt;div&gt;AppSettingsSection appSettings = config.AppSettings as AppSettingsSection;&lt;/div&gt;
&lt;div&gt;string logfile = appSettings.Settings[&amp;quot;logfile&amp;quot;].Value;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;// get connectionString&lt;/div&gt;
&lt;div&gt;string connectionString = config.ConnectionStrings.ConnectionStrings[&amp;quot;myConnString&amp;quot;].ConnectionString;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;.NET Configuration极其灵活，这里给出的只是一个非常简单的例子，深入研究容待后续。 &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+.NET+Configuration&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!457.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!457.entry</guid><pubDate>Tue, 20 Nov 2007 02:00:17 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!457/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!457.entry#comment</wfw:comment><dcterms:modified>2007-11-20T02:03:48Z</dcterms:modified></item><item><title>Simplified InstallUtil.exe</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!453.entry</link><description>&lt;div&gt;下面的代码演示了InstallUtil.exe的实现原理：&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;//////////////////////////////////&lt;br&gt;// SimpleInstall.cs&lt;br&gt;//    Simplified InstallUtil.exe&lt;br&gt;//////////////////////////////////&lt;/div&gt;
&lt;div&gt;using System;&lt;br&gt;using System.ComponentModel;&lt;br&gt;using System.Collections;&lt;br&gt;using System.Configuration.Install;&lt;br&gt;using System.IO;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;namespace SimpleInstallUtil&lt;br&gt;{&lt;br&gt;    public class SimpleInstall&lt;br&gt;    {&lt;br&gt;        public static void Main(string[] args)&lt;br&gt;        {&lt;br&gt;            ArrayList options = new ArrayList();&lt;br&gt;            string myOption;&lt;br&gt;            bool toUninstall = false;&lt;br&gt;            bool toPrintHelp = false;&lt;br&gt;            TransactedInstaller transactedInstaller = new TransactedInstaller();&lt;br&gt;            AssemblyInstaller assemblyInstaller;&lt;br&gt;            InstallContext installContext;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;            try&lt;br&gt;            {&lt;br&gt;                for (int i = 0; i &amp;lt; args.Length; i++)&lt;br&gt;                {&lt;br&gt;                    // process the arguments&lt;br&gt;                    if (args[i].StartsWith(&amp;quot;/&amp;quot;) || args[i].StartsWith(&amp;quot;-&amp;quot;))&lt;br&gt;                    {&lt;br&gt;                        // options&lt;br&gt;                        myOption = args[i].Substring(1);&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;                        // which option ?&lt;br&gt;                        if (String.Compare(myOption, &amp;quot;u&amp;quot;, true) == 0 || String.Compare(myOption, &amp;quot;uninstall&amp;quot;, true) == 0)&lt;br&gt;                        {&lt;br&gt;                            toUninstall = true;&lt;br&gt;                            continue;&lt;br&gt;                        }&lt;br&gt;                        if (String.Compare(myOption, &amp;quot;?&amp;quot;, true) == 0 || String.Compare(myOption, &amp;quot;help&amp;quot;, true) == 0)&lt;br&gt;                        {&lt;br&gt;                            toPrintHelp = true;&lt;br&gt;                            continue;&lt;br&gt;                        }&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;                        // other options, save it&lt;br&gt;                        options.Add(myOption);&lt;br&gt;                    }&lt;br&gt;                    else&lt;br&gt;                    {&lt;br&gt;                        // assembly to be installed&lt;br&gt;                        if (!File.Exists(args[i]))&lt;br&gt;                        {&lt;br&gt;                            Console.WriteLine(&amp;quot;Error: {0} - Assembly file doesn't exist.&amp;quot;, args[i]);&lt;br&gt;                            return;&lt;br&gt;                        }&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;                        // create an instance of 'AssemblyInstaller' that installs the given assembly&lt;br&gt;                        assemblyInstaller = new AssemblyInstaller(args[i], (string[])options.ToArray(typeof(string)));&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;                        // add the instance of 'AssemblyInstaller' to the 'TransactedInstaller'&lt;br&gt;                        transactedInstaller.Installers.Add(assemblyInstaller);&lt;br&gt;                    }&lt;br&gt;                }&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;                // help ?&lt;br&gt;                if (toPrintHelp || transactedInstaller.Installers.Count == 0)&lt;br&gt;                {&lt;br&gt;                    PrintHelp();&lt;br&gt;                    return;&lt;br&gt;                }&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;                installContext = new InstallContext(&amp;quot;SimpleInstall.log&amp;quot;, (string[])options.ToArray(typeof(string)));&lt;br&gt;                transactedInstaller.Context = installContext;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;                // install Or uninstall ?&lt;br&gt;                if (!toUninstall)&lt;br&gt;                {&lt;br&gt;                    transactedInstaller.Install(new Hashtable());&lt;br&gt;                }&lt;br&gt;                else&lt;br&gt;                {&lt;br&gt;                    transactedInstaller.Uninstall(null);&lt;br&gt;                }&lt;br&gt;            }&lt;br&gt;            catch (Exception exp)&lt;br&gt;            {&lt;br&gt;                Console.WriteLine(&amp;quot;Exception: {0}&amp;quot;, exp.Message.ToString());&lt;br&gt;            }&lt;br&gt;        }&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;        public static void PrintHelp()&lt;br&gt;        {&lt;br&gt;            Console.WriteLine(&amp;quot;Usage: SimpleInstall [/u | /uninstall] [option [...]] assembly [[option [...]] assembly [...]]&amp;quot;);&lt;br&gt;            Console.WriteLine(&amp;quot;SimpleInstall executes the installers in each of the given assembly.&amp;quot;);&lt;br&gt;            Console.WriteLine(&amp;quot;If /u or /uninstall option is given it uninstalls the assemblies.&amp;quot;);&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;由此可见，InstallUtil.exe的实现原理是比较简单的：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;1、分析命令行参数；&lt;/div&gt;
&lt;div&gt;2、构造AssemblyInstaller；&lt;/div&gt;
&lt;div&gt;3、由AssemblyInstaller构造TransactedInstaller；&lt;/div&gt;
&lt;div&gt;4、调用TransactedInstaller的Install或Uninstall方法完成安装或卸载。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;由此代码可以体会OOP的美妙之处：AssemblyInstaller和TransactedInstaller构成了InstallUtil.exe的核心，InstallUtil.exe只需要构造the instance of TransactedInstaller，然后调用其方法即可。而TransactedInstaller实例由多个AssemblyInstaller实例构成，所以任务归结为构造AssemblyInstaller的实例。而AssemblyInstaller实例的构造通过解析命令行参数完成。&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+Simplified+InstallUtil.exe&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!453.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!453.entry</guid><pubDate>Wed, 07 Nov 2007 03:23:50 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!453/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!453.entry#comment</wfw:comment><dcterms:modified>2007-11-07T03:23:50Z</dcterms:modified></item><item><title>Installer Tools (installutil.exe)</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!452.entry</link><description>&lt;div&gt;.NET Framework提供了InstallUtil.exe安装工具用于某些应用程序的安装。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;某些服务器应用程序除了传统的程序文件之外，还关联了一些资源，如消息队列（message queues）、事件日志（event logs）、性能计数器（performance counters）等，在部署应用程序时，必须创建这些相关资源，而在卸载应用程序时，也必须同时删除这些资源。.NET Framework提供了安装组件（installer components）用于完成这些任务。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Installer components是导出自System.Configuration.Install.Installer的用户自定义Class，带有[RunInstaller(true)] attribute：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;[RunInstaller(true)]&lt;/div&gt;
&lt;div&gt;public class MyInstaller&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;    // .....&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;System.Configuration.Install.Installer类实现了四个方法：Install, Commit, Rollback, Uninstall，用于实现事务性的（transacted）安装/卸载功能。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;InstallUtil.exe安装工具通过反射方法获取要安装的程序集的installer component，调用其中的Install进行安装，如果Install执行成功，则最后执行Commit提交安装；如果在执行Install的过程中出现错误，则执行Rollback完成回滚，使系统恢复到安装前的状态。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;InstallUtil.exe /u 调用Uninstall方法完成卸载。注意：卸载是非事务性的，亦即如果卸载过程中出现错误，则忽略，继续卸载其余部分。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;InstallUtil.exe安装完成后，在当前目录产生三个文件：&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;InstallUtil.InstallLog&lt;br&gt;该文件含有安装过程的描述。 
&lt;li&gt;&lt;em&gt;assemblyname&lt;/em&gt;.InstallLog&lt;br&gt;该文件含有安装过程的Commit阶段的信息。 
&lt;li&gt;&lt;em&gt;assemblyname&lt;/em&gt;.InstallState&lt;br&gt;该文件含有卸载时需要的信息。注意：卸载应用程序时，当前目录必须含有该文件，否则卸载失败。&lt;/ul&gt;
&lt;p&gt;由此简单说明可以看出，.NET Framework通过InstallUtil.exe/Installer Components对服务器端应用程序提供了一个框架性的安装工具，方便了Windows Service这类服务器端应用程序的开发。 
&lt;p&gt;下面的例子演示了Installer Class的用法： 
&lt;p&gt;using System;&lt;br&gt;using System.Collections;&lt;br&gt;using System.ComponentModel;&lt;br&gt;using System.Configuration.Install; 
&lt;p&gt;namespace InstallerDemo&lt;br&gt;{&lt;br&gt;    // RunInstallerAttribute declares MyInstaller class is an installer component.&lt;br&gt;    [RunInstaller(true)]&lt;br&gt;    public class MyInstaller : Installer&lt;br&gt;    {&lt;br&gt;        public MyInstaller() : base()&lt;br&gt;        {&lt;br&gt;            // Attach the 'BeforeInstall' event&lt;br&gt;            this.BeforeInstall += MyInstallerBeforeInstall; 
&lt;p&gt;            // Attach the 'AfterInstall' event&lt;br&gt;            this.AfterInstall += MyInstallerAfterInstall; 
&lt;p&gt;            // Attach the 'Committed' event&lt;br&gt;            this.Committed += MyInstallerCommitted; 
&lt;p&gt;            // Attach the 'Committing' event&lt;br&gt;            this.Committing += MyInstallerCommitting;&lt;br&gt;        } 
&lt;p&gt;        // Event handler for 'BeforeInstall'&lt;br&gt;        private void MyInstallerBeforeInstall(object sender, InstallEventArgs args)&lt;br&gt;        {&lt;br&gt;            Console.WriteLine(&amp;quot;Before install...&amp;quot;);&lt;br&gt;        } 
&lt;p&gt;        // Event handler for 'AfterInstall'&lt;br&gt;        private void MyInstallerAfterInstall(object sender, InstallEventArgs args)&lt;br&gt;        {&lt;br&gt;            Console.WriteLine(&amp;quot;After install.&amp;quot;);&lt;br&gt;        } 
&lt;p&gt;        // Event handler for 'Committed'&lt;br&gt;        private void MyInstallerCommitted(object sender, InstallEventArgs args)&lt;br&gt;        {&lt;br&gt;            Console.WriteLine(&amp;quot;Installer committed.&amp;quot;);&lt;br&gt;        }&lt;br&gt;        // Event handler for 'Committing'&lt;br&gt;        private void MyInstallerCommitting(object sender, InstallEventArgs args)&lt;br&gt;        {&lt;br&gt;            Console.WriteLine(&amp;quot;Installer committing...&amp;quot;);&lt;br&gt;        } 
&lt;p&gt;        // Override the 'Install' method&lt;br&gt;        public override void Install(IDictionary savedState)&lt;br&gt;        {&lt;br&gt;            base.Install(savedState);&lt;br&gt;            Console.WriteLine(&amp;quot;Installing...&amp;quot;);&lt;br&gt;        } 
&lt;p&gt;        // Override the 'Commit' method&lt;br&gt;        public override void Commit(IDictionary savedState)&lt;br&gt;        {&lt;br&gt;            base.Commit(savedState);&lt;br&gt;            Console.WriteLine(&amp;quot;Committing...&amp;quot;);&lt;br&gt;        } 
&lt;p&gt;        // Override the 'Rollback' method&lt;br&gt;        public override void Rollback(IDictionary savedState)&lt;br&gt;        {&lt;br&gt;            base.Rollback(savedState);&lt;br&gt;            Console.WriteLine(&amp;quot;Rolling back...&amp;quot;);&lt;br&gt;        } 
&lt;p&gt;        public static void Main()&lt;br&gt;        {&lt;br&gt;            // ......&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;} 
&lt;p&gt;例子中注册事件处理的代码利用了C#的简化语法： 
&lt;p&gt;this.BeforeInstall += MyInstallerBeforeInstall; 
&lt;p&gt;完整的语法应该是： 
&lt;p&gt;this.BeforeInstall += new InstallEventHandler(MyInstallerBeforeInstall); 
&lt;p&gt;由此可见，C# syntactical sugar为开发人员（特别是熟悉C/C++的开发人员）提供了莫大的便利，使得代码更加自然与直观。
&lt;p&gt;上述的InstallEventHandler的声明是：
&lt;p&gt;public delegate void InstallEventHandler(Object sender, InstallEventArgs args);
&lt;p&gt;根据此delegate的声明，可知MyInstallerBeforeInstall的声明必须是：
&lt;p&gt;void MyInstallerBeforeInstall(Object sender, InstallEventArgs args);&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+Installer+Tools+(installutil.exe)&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!452.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!452.entry</guid><pubDate>Tue, 06 Nov 2007 09:51:57 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!452/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!452.entry#comment</wfw:comment><dcterms:modified>2007-11-07T02:00:22Z</dcterms:modified></item><item><title>Windows Service with C#</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!451.entry</link><description>&lt;div&gt;最近需要用C#写一个Windows Service（以前称为NT Service），Google了一下，发现很多相关文章都是依据Visual Studio .NET的，但因为VS .NET隐含了很多细节，对我们搞清Windows Service with C#的实现机制没有多大帮助。下面给出一个手写的Windows Service with C#的skeleton：&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;// file: cservice.cs                &lt;/div&gt;
&lt;div&gt;using System;&lt;br&gt;using System.Collections;&lt;br&gt;using System.ComponentModel;&lt;br&gt;using System.Diagnostics;&lt;br&gt;using System.ServiceProcess;&lt;br&gt;using System.Configuration.Install;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;namespace Levensoft.Service.WindowsService&lt;br&gt;{&lt;br&gt;    // Windows Service class&lt;br&gt;    public class MyFirstService : System.ServiceProcess.ServiceBase&lt;br&gt;    {&lt;br&gt;        public MyFirstService()&lt;br&gt;        {&lt;br&gt;            this.CanPauseAndContinue = true;&lt;br&gt;            this.CanShutdown = true;&lt;br&gt;            this.CanHandleSessionChangeEvent = false;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;            this.ServiceName = &amp;quot;MyFirstService&amp;quot;;&lt;br&gt;        }&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;        protected override void OnStart(string[] args)&lt;br&gt;        {&lt;br&gt;        }&lt;/div&gt;
&lt;div&gt;        protected override void OnStop()&lt;br&gt;        {&lt;br&gt;        }&lt;/div&gt;
&lt;div&gt;        protected override void OnContinue()&lt;br&gt;        {&lt;br&gt;        }&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;        public static void Main()&lt;br&gt;        {&lt;br&gt;            ServiceBase[] servicesToRun;&lt;/div&gt;
&lt;div&gt;            servicesToRun = new ServiceBase[] {new Levensoft.Service.WindowsService.MyFirstService()};&lt;br&gt;            ServiceBase.Run(servicesToRun);&lt;br&gt;        }&lt;br&gt;    }&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;    // Windows Service Installer Components&lt;br&gt;    [RunInstaller(true)]&lt;br&gt;    public class ProjectInstaller : System.Configuration.Install.Installer&lt;br&gt;    {&lt;br&gt;        private ServiceProcessInstaller myServiceProcessInstaller;&lt;br&gt;        private ServiceInstaller myServiceInstaller;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;        public ProjectInstaller()&lt;br&gt;        {&lt;br&gt;            this.myServiceProcessInstaller = new ServiceProcessInstaller();&lt;br&gt;            this.myServiceInstaller = new ServiceInstaller();&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;            // myServiceProcessInstaller&lt;br&gt;            // Account or Username &amp;amp; Password&lt;br&gt;            this.myServiceProcessInstaller.Account = ServiceAccount.LocalSystem;&lt;br&gt;            this.myServiceProcessInstaller.Username = null;&lt;br&gt;            this.myServiceProcessInstaller.Password = null;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;            // myServiceInstaller&lt;br&gt;            // ServiceName &amp;amp; StartType&lt;br&gt;            this.myServiceInstaller.ServiceName = &amp;quot;MyFirstService&amp;quot;;&lt;br&gt;            this.myServiceInstaller.StartType = ServiceStartMode.Automatic;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;            // ProjectInstaller&lt;br&gt;            this.Installers.AddRange(new Installer[] {this.myServiceProcessInstaller, this.myServiceInstaller});&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;}&lt;br&gt;&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;1、编译&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;csc cservice.cs&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;2、安装&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;installutil cservice.exe&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;3、启动服务&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;net start MyFirstService&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;4、停止服务&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;net stop MyFirstService&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;5、卸载&lt;/div&gt;
&lt;div&gt;    &lt;/div&gt;
&lt;div&gt;installutil /u cservice.exe&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+Windows+Service+with+C%23&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!451.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!451.entry</guid><pubDate>Tue, 06 Nov 2007 07:47:47 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!451/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!451.entry#comment</wfw:comment><dcterms:modified>2007-11-07T05:35:43Z</dcterms:modified></item><item><title>Effective C# -- part two</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!447.entry</link><description>&lt;div&gt;Item 1: Always Use Properties Instead of Accessible Data Members&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;C#对property提供了语言级的支持（The C# language promoted properties from an ad-hoc convention to a first-class language feature.）。作者从三个方面论述应该使用properties，而不是public data members。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;1、.NET Framework Class Library中UI控件的绑定机制只支持properties，而不是public data members。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;txtUserName.DataBindings.Add(&amp;quot;Name&amp;quot;, userObject, &amp;quot;Name&amp;quot;);&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;这里的txtUserName是一个Web Forms Control或Windows Forms Control，这行代码将userObject的Name property绑定到txtUserName的Name属性。userObject的Name必须是property，而不能是public data member。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;2、使用property可以加入检测代码，从而保证类型安全。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;public class User&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;    private string _name;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;    public string Name&lt;/div&gt;
&lt;div&gt;    {&lt;/div&gt;
&lt;div&gt;        get { return _name; }&lt;/div&gt;
&lt;div&gt;        set&lt;/div&gt;
&lt;div&gt;        {&lt;/div&gt;
&lt;div&gt;            if (value == null || value.Length == 0)&lt;/div&gt;
&lt;div&gt;            {&lt;/div&gt;
&lt;div&gt;                throw new ArgumentException(&amp;quot;Name can not be blank.&amp;quot;);&lt;/div&gt;
&lt;div&gt;            }&lt;/div&gt;
&lt;div&gt;            _name = value;&lt;/div&gt;
&lt;div&gt;        }&lt;/div&gt;
&lt;div&gt;    }&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;    // .........&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;上述代码中的空值检测，如果Name不是property而是public data member，是无法或很难实现的。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;3、使用property使得客户端代码更加自然。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;User userObject = new User();&lt;/div&gt;
&lt;div&gt;string userName = userObject.Name;&lt;/div&gt;
&lt;div&gt;userObject.Name = &amp;quot;David&amp;quot;;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;使用property而不是get/set method call，使得上述代码more natural and intuitive。这是C#非常得意的事情。Scott Wiltamuth（C# Design Team Member）在《Inside C#》的序言中指出：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;if the framework supports properties and the language doesn't, incrementing a property is awkward (for example, o.SetValue(o.GetVaue() + 1)). If the language also supports properties, the operation is simple (o.Value++).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;接着，作者讨论了一些更加深入的内容，如parameterized property (indexer)，read-only/read-write/write-only property，virtual property，以及将Name从public data member转换为property而可能会带来的问题等，从而结束本条目。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;对property的语言级支持是C#成为面向组件的语言（component-oriented programming language）的重要特征之一。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;关于property，也存在一些争论。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;1、如果一个Class含有大量的data members，使用property机制会非常繁琐（tedious），也会降低代码性能。这是C++/Java经常揶揄C#的问题。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;2、property的intuitive语法在产生pretty code的同时，有时也会带来一些问题。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;User userObject = new User();&lt;/div&gt;
&lt;div&gt;someMethod(ref userObject.Name);    // illegal -- userObject.Name has no storage!&lt;/div&gt;
&lt;div&gt;//........&lt;/div&gt;
&lt;div&gt;public void someMethod(ref string someVariable)&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;    someVariable = &amp;quot;Some String&amp;quot;;&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;property是通过get/set机制实现的，所以userObject.Name不是一个变量，而someMethod()要求一个有地址的变量，所以userObject.Name不能用作someMethod()的参数，但从语法上看是没有问题的。这是C#语言中语法构造破坏语义的一个典型例子。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;3、Jeffrey Richter在《CLR via C#》中详细讨论了property的问题，其中大部分都与property的“语法构造破坏语义”有关。所以Jeffrey最后说：But I'd want the compiler to use syntax that is different from field access syntax so that programmers really understand what they are doing—a method call.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;4、对于远程访问的Class（继承自System.MarshalByRefObject），通过property访问Class的data members（fields）是非常不经济的。不过，这不是property的问题，即使直接的data member access也有同样的问题。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;就像打开窗子，新鲜空气和蚊子、苍蝇都会一起进来一样，property在提供语法便利的同时，也会存在一些问题，重要的是要意识到这些问题，从而尽量规避之。从这点上来讲，我觉得《Effective C#》的Item 1没有把property存在的问题说透。&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+Effective+C%23+--+part+two&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!447.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!447.entry</guid><pubDate>Sat, 27 Oct 2007 05:49:46 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!447/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!447.entry#comment</wfw:comment><dcterms:modified>2007-10-27T06:40:43Z</dcterms:modified></item><item><title>Effective C# -- part one</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!446.entry</link><description>&lt;div&gt;“从众”可能是人类共有的心理。继Scott Meyers获得巨大成功的《Effective C++》（&lt;a href="http://www.artima.com/cppsource/top_cpp_people.html" target="_blank"&gt;Scott Meyers以三册《Effective》进入C++重要人物Top 5排行榜&lt;/a&gt;）之后，《Effective Java》、《Effective C#》相继出炉，但能否像《Effective C++》那样成功呢？不敢妄言，需要时间。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;《Effective C#》第一章，作者在开篇中写到：&lt;/div&gt;
&lt;div&gt;Why should you change what you are doing today if it works? The answer is that you can be better. You change tools or languages because you can be more productive. You don't realize the expected gains if you don't change your habits. This is harder when the new language, C#, has so much in common with a familiar language, such as C++ or Java. It's easy to fall back on old habits. Most of these old habits are fine. The C# language designers want you to be able to leverage your knowledge in these languages. However, they also added and changed some elements to provide better integration with the Common Language Runtime (CLR), and provide better support for component-oriented development. This chapter discusses those habits that you should change and what you should do instead.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;西方人的思维与我们确实不同，开篇第一句话：&lt;/div&gt;
&lt;div&gt;Why should you change what you are doing today if it works? The answer is that you can be better.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;一般我们可能不会这样想，也不会这样说，而是会讲一篇云里雾里的大道理。实际上，有理不在言多，这么看似轻描淡写的一句话，就概括了整本书的精髓！&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;题外话：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;写到《Effective C++》，就顺便把第三版拿了出来。《Effective C++》第三版英文版由电子工业出版社出版，封面设计简洁、素雅、大方，内页的印刷非常清楚，而且更值得称道的是，虽然也不能免俗，将序言译成了中文，但仍然附了原文。整本书无可挑剔！&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;有人说，看一个人有没有修养（教养），从他进门的动作就可以看出来。两个人同时进门，你是不是让一步？是不是彬彬有礼？有人从管理学上拈出“细节”一词，可谓精道。不能免俗地比附一下，书对于出版者也是一种“门”，出版者是否有大家风范，不是看你抢着出了多少书，而是更多地反映在一些小的细节上。如《Effective C++》第三版英文版在版权页最后注明：凡购买电子工业出版社的图书，如有缺损问题，请向购买书店调换，若书店售缺，请与本社发行部联系。联系电话：（010）68279077。有很多出版社都将缺损书的调换推给印刷厂，我认为这是一种不负责任的做法。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;电子工业出版社所出计算机类的图书不算很多（我手头只有这本《Effective C++》），但就本书而言，已足见出版者的细心与周到。本书的出版，终于使Scott Meyers的书形式与内容“门当户对”了。最后以内容简介中的一小段话结尾罢：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;C++是真正程序员的语言，背后有着精深的思想与无与伦比的表达能力，这使得它具有类似宗教般的魅力。希望这本书能够帮助您跨越C++的重重险阻，领略高处才有的壮美风光，做一个成功而快乐的C++程序员。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;P.S.&lt;/div&gt;
&lt;div&gt;《Effective C++》第三版英文版责任编辑：周筠。Thanks a lot for this pretty book.&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+Effective+C%23+--+part+one&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!446.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!446.entry</guid><pubDate>Fri, 26 Oct 2007 17:57:11 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!446/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!446.entry#comment</wfw:comment><dcterms:modified>2007-10-27T06:53:39Z</dcterms:modified></item><item><title>一个C#的例子 (An Example of C#)</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!444.entry</link><description>&lt;p&gt;using System;&lt;br&gt;using System.Collections.Generic; 
&lt;p&gt;namespace CLRviaCSharp&lt;br&gt;{&lt;br&gt;  public sealed class Point : IComparable&amp;lt;Point&amp;gt;&lt;br&gt;  {&lt;br&gt;    private int m_x, m_y; 
&lt;p&gt;    public Point (int x, int y)&lt;br&gt;    {&lt;br&gt;      m_x = x;&lt;br&gt;      m_y = y;&lt;br&gt;    } 
&lt;p&gt;    // implement IComparable.CompareTo()&lt;br&gt;    public int CompareTo(Point other)&lt;br&gt;    {&lt;br&gt;      return Compare(this, other);&lt;br&gt;    } 
&lt;p&gt;    // operator overloading&lt;br&gt;    public static bool operator &amp;lt;(Point me, Point other)&lt;br&gt;    {&lt;br&gt;      return Compare(me, other) &amp;lt; 0;&lt;br&gt;    }&lt;br&gt;    public static bool operator &amp;lt;=(Point me, Point other)&lt;br&gt;    {&lt;br&gt;      return Compare(me, other) &amp;lt;= 0;&lt;br&gt;    }&lt;br&gt;    public static bool operator &amp;gt;(Point me, Point other)&lt;br&gt;    {&lt;br&gt;      return Compare(me, other) &amp;gt; 0;&lt;br&gt;    }&lt;br&gt;    public static bool operator &amp;gt;=(Point me, Point other)&lt;br&gt;    {&lt;br&gt;      return Compare(me, other) &amp;gt;= 0;&lt;br&gt;    } 
&lt;p&gt;    // override Object.ToString()&lt;br&gt;    public override String ToString()&lt;br&gt;    {&lt;br&gt;      return String.Format(&amp;quot;({0}, {1})&amp;quot;, m_x.ToString(), m_y.ToString());&lt;br&gt;    } 
&lt;p&gt;    // static helper method for points comparison&lt;br&gt;    public static int Compare(Point p, Point q)&lt;br&gt;    {&lt;br&gt;      return Math.Sign(Math.Sqrt(p.m_x * p.m_x + p.m_y * p.m_y) - Math.Sqrt(q.m_x * q.m_x + q.m_y * q.m_y));&lt;br&gt;    }&lt;br&gt;    public static int CompareDESC(Point p, Point q)&lt;br&gt;    {&lt;br&gt;      return -Compare(p, q);&lt;br&gt;    }&lt;br&gt;  } 
&lt;p&gt;  public class test&lt;br&gt;  {&lt;br&gt;    public static void Main()&lt;br&gt;    {&lt;br&gt;      Point[] points = new Point[] {new Point(3, 3), new Point(1, 2)}; 
&lt;p&gt;      // original points&lt;br&gt;      Console.WriteLine(&amp;quot;Points:&amp;quot;);&lt;br&gt;      foreach (Point p in points)&lt;br&gt;      {&lt;br&gt;        Console.WriteLine(p);&lt;br&gt;      } 
&lt;p&gt;      // ordered by IComparable.CompareTo()&lt;br&gt;      if (points[0].CompareTo(points[1]) &amp;gt; 0)&lt;br&gt;      {&lt;br&gt;        Swap&amp;lt;Point&amp;gt;(ref points[0], ref points[1]);&lt;br&gt;      }&lt;br&gt;      Console.WriteLine(&amp;quot;Points from closest (0, 0) to farthest:&amp;quot;);&lt;br&gt;      foreach (Point p in points)&lt;br&gt;      {&lt;br&gt;        Console.WriteLine(p);&lt;br&gt;      } 
&lt;p&gt;      // ordered by overloaded operator &amp;lt;=&lt;br&gt;      // it is more natural than CompareTo()&lt;br&gt;      if (points[0] &amp;lt;= points[1])&lt;br&gt;      {&lt;br&gt;        Swap&amp;lt;Point&amp;gt;(ref points[0], ref points[1]);&lt;br&gt;      }&lt;br&gt;      Console.WriteLine(&amp;quot;Points from farthest to closest (0, 0):&amp;quot;);&lt;br&gt;      foreach (Point p in points)&lt;br&gt;      {&lt;br&gt;        Console.WriteLine(p);&lt;br&gt;      } 
&lt;p&gt;      // ordered by Array.Sort()&lt;br&gt;      Array.Sort(points, Point.Compare);&lt;br&gt;      Console.WriteLine(&amp;quot;Points from closest (0, 0) to farthest:&amp;quot;);&lt;br&gt;      foreach (Point p in points)&lt;br&gt;      {&lt;br&gt;        Console.WriteLine(p);&lt;br&gt;      } 
&lt;p&gt;      // simulate Array.Sort()&lt;br&gt;      // Point.CompareDESC is a function (method in C#)&lt;br&gt;      // which would be tranformed to a delegate by C# compiler&lt;br&gt;      Sort&amp;lt;Point&amp;gt;(points, Point.CompareDESC);&lt;br&gt;      Console.WriteLine(&amp;quot;Points from farthest to closest (0, 0):&amp;quot;);&lt;br&gt;      foreach (Point p in points)&lt;br&gt;      {&lt;br&gt;        Console.WriteLine(p);&lt;br&gt;      } 
&lt;p&gt;      // this time, we define a delegate explicitly&lt;br&gt;      Comparison&amp;lt;Point&amp;gt; cmpDelegate = new Comparison&amp;lt;Point&amp;gt;(Point.Compare);&lt;br&gt;      Sort&amp;lt;Point&amp;gt;(points, cmpDelegate);&lt;br&gt;      Console.WriteLine(&amp;quot;Points from closest (0, 0) to farthest:&amp;quot;);&lt;br&gt;      foreach (Point p in points)&lt;br&gt;      {&lt;br&gt;        Console.WriteLine(p);&lt;br&gt;      }&lt;br&gt;    } 
&lt;p&gt;    // simulate Array.Sort&amp;lt;T&amp;gt;(T[] array, Comparison&amp;lt;T&amp;gt; comparison)&lt;br&gt;    // Comparison&amp;lt;T&amp;gt; is a generic delegate:&lt;br&gt;    // public delegate int Comparison&amp;lt;T&amp;gt; (T x, T y)&lt;br&gt;    public static void Sort&amp;lt;T&amp;gt;(T[] pList, Comparison&amp;lt;T&amp;gt; cmp)&lt;br&gt;    {&lt;br&gt;      // extremely simplified sort algorithm&lt;br&gt;      for (int i = 1; i &amp;lt; pList.Length; i++)&lt;br&gt;      {&lt;br&gt;        // cmp is a delegate!&lt;br&gt;        // cmp(pList[i - 1], pList[i]) is also ok and more natural&lt;br&gt;        if (cmp.Invoke(pList[i - 1], pList[i]) &amp;gt; 0)&lt;br&gt;        {&lt;br&gt;          Swap&amp;lt;T&amp;gt;(ref pList[i - 1], ref pList[i]);&lt;br&gt;        }&lt;br&gt;      }&lt;br&gt;    } 
&lt;p&gt;    // utility method to swap two objects&lt;br&gt;    public static void Swap&amp;lt;T&amp;gt;(ref T p, ref T q)&lt;br&gt;    {&lt;br&gt;      T temp = p;&lt;br&gt;      p = q;&lt;br&gt;      q = temp;&lt;br&gt;    }&lt;br&gt;  }&lt;br&gt;} 
&lt;p&gt;这个例子源自Jeffrey Richter《CLR via C#》。原例是讲接口继承的，为了演示C#语言的几个特性，做了些改动。 
&lt;p&gt;1、通过operator overloading，Point实现了&amp;lt;、&amp;lt;=、&amp;gt;、&amp;gt;=几个更加自然的比较运算。对比points[0].CompareTo(points[1])和points[0] &amp;lt; points[1]。 
&lt;p&gt;2、在定义了Point的“比较”操作的基础上，通过generic method，Point数组实现了排序算法。 
&lt;p&gt;3、首先，利用Array.Sort()，可以很方便地完成Point[]的排序。 
&lt;p&gt;4、为了研究Array.Sort()的机制，我们实现了自己的Sort()方法。Sort method需要一个callback。C#中没有指针的概念（限于safe code），所以不能像C/C++那样通过将一个指向函数的指针作为参数而为Sort提供一个callback。C#实现callback的机制是delegate。 
&lt;p&gt;5、例子演示了两种callback语法：一种接近于C/C++的pointer points to function的语法；一种是正规的delegate语法。对于C/C++程序员来说，正规的delegate语法非常别扭，这也是C#提供简化语法的原因！ 
&lt;p&gt;6、注意Sort()内的cmp的调用（invoke）语法：可以直接应用cmp(pList[i-1], pList[i])语法调用callback，也可以用cmp.Invoke(pList[i-1], pList[i])这种正规的delegate调用语法。但这种方式没有前一种方式自然，这也是C#为C/C++程序员简化语法的原因罢。Don Box对这种简化提出了异议：In my opinion, this slight obfuscation adds little to the usability of delegate. -- &lt;em&gt;Don Box, Essential .NET, p.185&lt;/em&gt; 
&lt;p&gt;7、C++ STL的理念是Program = Algorithm + Data Structure，算法可以应用于任何实现了某种Iterator的Container上，从而实现算法复用。C#中没有全局函数的概念，从而导致算法和数据结构无法分离，如Array有自己的Sort()，List&amp;lt;T&amp;gt;也有自己的Sort()，等等。本例中的Swap&amp;lt;T&amp;gt;就是一个例子，所有的排序算法都需要Swap，所以都需要实现自己的Swap。这种reinvent-the-wheel的工作实在有违generic的精神。 
&lt;p&gt; 8、Sort()之所以需要一个callback，是因为Sort本身不知道如何去比较所操作的数据对象（points），这是数据对象自己才能决定的事情，这也是一种专业化分工罢。无论是现实世界还是程序世界，都是work effectively的不二法门。&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+%e4%b8%80%e4%b8%aaC%23%e7%9a%84%e4%be%8b%e5%ad%90+(An+Example+of+C%23)&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!444.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!444.entry</guid><pubDate>Wed, 17 Oct 2007 18:23:33 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!444/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!444.entry#comment</wfw:comment><dcterms:modified>2007-10-24T16:59:32Z</dcterms:modified></item><item><title>SQL Server 2005数据类型的一点注记</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!357.entry</link><description>&lt;p&gt;在SQL Server 2000中，存储大型文本或二进制数据（BLOB）的数据类型有text、ntext、image三种：
&lt;p&gt;text：用于存储长度不定的大型ANSI文本，最多可达到231-1（2,147,483,647）个字符（character）。
&lt;p&gt;ntext：用于存储长度不定的大型Unicode文本，最多可达到230-1（1,073,741,823）个字符（character）。由于Unicode以两个字节表示一个字符，所以231-1个字节只能表示230-1个字符。
&lt;p&gt;image：用于存储长度不定的大型二进制数据，最多可达到231-1（2,147,483,647）个字节（byte）。
&lt;p&gt;但在SQL Server 2005中，这些数据类型已不推荐使用，在未来的版本中将不再支持。取而代之的分别是varchar(max)、nvarchar(max)、varbinary(max)。这些数据类型为处理大型数据（SQL Server 2005中称为Large-value data types）提供了更好的支持。比如，原来由于不能声明text、ntext和image类型的变量，所以不能在Transact-SQL中处理这些类型的数据。而现在，你可以声明varchar(max)、nvarchar(max)和varbinary(max)类型的变量，从而可以在Transact-SQL中处理大型文本或二进制数据。
&lt;p&gt;遗憾的是，.NET 2.0中的数据类型并没有做到与SQL Server 2005同步，仍然停留在SQL Server 2000的水平，与text对应的是SqlDbType.Text，与ntext对应的是SqlDbType.NText，与image对应的是SqlDbType.Image，而没有与varchar(max)、nvarchar(max)、varbinary(max)对应的SqlDbType枚举值。
&lt;p&gt;.NET 3.0是否已与SQL Server 2005同步？尚不清楚。&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+SQL+Server+2005%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b%e7%9a%84%e4%b8%80%e7%82%b9%e6%b3%a8%e8%ae%b0&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!357.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!357.entry</guid><pubDate>Mon, 21 May 2007 01:24:15 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!357/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!357.entry#comment</wfw:comment><dcterms:modified>2007-05-21T01:24:15Z</dcterms:modified></item><item><title>关于UTF-8的一点注记</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!345.entry</link><description>&lt;div&gt;First of all, &lt;strong&gt;CLR via C#&lt;/strong&gt;! I've got it! Thanks soooooooooooooooooo much!&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;如下两个文件，a.htm和a.js。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;a.htm&lt;/div&gt;
&lt;div&gt;&amp;lt;html&amp;gt;&lt;/div&gt;
&lt;div&gt;&amp;lt;head&amp;gt;&lt;/div&gt;
&lt;div&gt;&amp;lt;meta http-equiv=&amp;quot;content-type&amp;quot; content=&amp;quot;text/html;charset=utf-8&amp;quot; /&amp;gt;&lt;/div&gt;
&lt;div&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;a.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/div&gt;
&lt;div&gt;&amp;lt;/head&amp;gt;&lt;/div&gt;
&lt;div&gt;&amp;lt;body&amp;gt;&lt;/div&gt;
&lt;div&gt;&amp;lt;div id=&amp;quot;info&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/div&gt;
&lt;div&gt;&amp;lt;/body&amp;gt;&lt;/div&gt;
&lt;div&gt;&amp;lt;/html&amp;gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;a.js&lt;/div&gt;
&lt;div&gt;function showMessage()&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;    var info = document.getElementById(&amp;quot;info&amp;quot;);&lt;/div&gt;
&lt;div&gt;    if (info)&lt;/div&gt;
&lt;div&gt;    {&lt;/div&gt;
&lt;div&gt;        info.innerHTML = &amp;quot;信息提示...&amp;quot;;&lt;/div&gt;
&lt;div&gt;    }&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;则a.js必须明确存为UTF-8格式，showMessage()才能正确显示中文，如果a.js默认保存为ANSI格式，则showMessage()显示乱码。&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+%e5%85%b3%e4%ba%8eUTF-8%e7%9a%84%e4%b8%80%e7%82%b9%e6%b3%a8%e8%ae%b0&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!345.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!345.entry</guid><pubDate>Tue, 10 Apr 2007 13:21:21 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!345/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!345.entry#comment</wfw:comment><dcterms:modified>2007-04-10T13:24:49Z</dcterms:modified></item><item><title>GUID</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!343.entry</link><description>&lt;div&gt;UUID是分布式计算环境中用于标识对象的唯一标识符（Universally Unique IDentifier），后来Microsoft在COM中为了唯一标识Class, Interface, Object, etc.而引入了GUID（Globally Unique IDentifier）并提供了API来创建GUID：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;1、SQL Server&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;SQL Server提供了NEWID()函数用于生成GUID。&lt;/div&gt;
&lt;div&gt;可以用GUID来作为记录的唯一标识符：&lt;/div&gt;
&lt;div&gt;CREATE TABLE myTable (&lt;/div&gt;
&lt;div&gt;    id uniqueidentifier NOT NULL,&lt;/div&gt;
&lt;div&gt;    ...&lt;/div&gt;
&lt;div&gt;)&lt;/div&gt;
&lt;div&gt;ALTER TABLE myTable ADD DEFAULT (NEWID()) FOR id&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;2、Visual C++&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;COM中提供了CoCreateGuid()方法用于创建GUID：&lt;/div&gt;
&lt;div&gt;STDMETHODIMP CGuidObject::GetGUID(BSTR* bstrGUID)&lt;br&gt;{&lt;br&gt;    HRESULT  hr = S_OK;&lt;br&gt;    GUID  guid;&lt;/div&gt;
&lt;div&gt;    hr = CoCreateGuid(&amp;amp;guid);&lt;br&gt;    if (hr == S_OK) {&lt;br&gt;        OLECHAR  szGUID[256];&lt;br&gt;        StringFromGUID2(guid, szGUID, sizeof(szGUID));&lt;br&gt;        *bstrGUID = SysAllocString(szGUID);&lt;br&gt;    }&lt;br&gt;    return hr;&lt;br&gt;}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;3、C#&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;.NET在System中提供了Guid结构，其NewGuid()方法可以用于创建GUID：&lt;/div&gt;
&lt;div&gt;using System;&lt;/div&gt;
&lt;div&gt;public class myGuid&lt;br&gt;{&lt;br&gt;    public static void Main()&lt;br&gt;    {&lt;br&gt;        Guid myGuid = Guid.NewGuid();&lt;br&gt;        Console.WriteLine(&amp;quot;GUID:{0}&amp;quot;, myGuid.ToString());&lt;br&gt;    }&lt;br&gt;}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;注记：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;1、如果Table中的id字段为uniqueidentifier类型，则通过下面的代码取到id的值：&lt;/div&gt;
&lt;div&gt;SqlDataReader rdr = cmd.ExecuteReader();&lt;/div&gt;
&lt;div&gt;if (rdr.Read())&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;    string sGUID = ((System.Guid)rdr[&amp;quot;id&amp;quot;]).ToString();&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;2、SQL Server中的NEWID()函数和C#中的System.Guid.NewGuid()方法有两点区别：&lt;/div&gt;
&lt;div&gt;1) NEWID()返回的格式是大写形式，NewGuid()返回的格式是小写形式；&lt;/div&gt;
&lt;div&gt;2) NEWID()带有大括号&amp;quot;{}&amp;quot;，NewGuid()则没有。&lt;/div&gt;
&lt;div&gt;具体而言，NEWID()的格式是&amp;quot;{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}&amp;quot;，NewGuid()的格式是&amp;quot;xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&amp;quot;。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;SQL Server在将varchar格式的“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”字符串转换为uniqueidentifier类型时，自动转换为NEWID()的格式。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;3、&lt;a href="http://www.dotnet247.com/247reference/msgs/57/289465.aspx"&gt;有人报告了一个“匪夷所思”的问题&lt;/a&gt;：在获取类型为uniqueidentifier的参数返回值（cmd.Parameters[&amp;quot;@valueID&amp;quot;].Value）时，如果该值为Null（DbNull），则cmd.Parameters[&amp;quot;@valueID&amp;quot;].Value的类型为System.Guid，如果该值不为Null，则其类型为SqlGuid！&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;我没试过，不知道是否真的如此。录在这里，仅做参考。&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+GUID&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!343.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!343.entry</guid><pubDate>Thu, 05 Apr 2007 06:22:48 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!343/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!343.entry#comment</wfw:comment><dcterms:modified>2007-04-14T15:24:01Z</dcterms:modified></item><item><title>Waiting for CLR via C#......</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!338.entry</link><description>&lt;div&gt;前段时间听朋友介绍，说《CLR via C#》是amazon.com上被评为五星级的书，今天突然想起来，就去看了看，果然……&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;《CLR via C#》的作者是大名鼎鼎的Jeffrey Richter，难怪评价如此之高！&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;About Jeffrey Richter:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Jeffrey Richter is a co-founder of Wintellect, a training, debugging, and consulting firm dedicated to helping companies build better software, faster.   Over the years, Jeff has consulted for many companies including Intel, DreamWorks and Microsoft. In fact, for Microsoft, he has contributed both design and code to the following products: Windows (all 32-bit and 64-bit versions), Visual Studio .NET, Microsoft Office, TerraServer, the .NET Framework, &amp;quot;Longhorn&amp;quot; and &amp;quot;Indigo&amp;quot;. Even today, Jeff is still consulting with Microsoft's .NET Framework team (since October 1999) and XML Web Services and Messaging Team (&amp;quot;Indigo&amp;quot;) (since January 2003).&lt;/div&gt;
&lt;div&gt;&lt;br&gt; &lt;/div&gt;
&lt;div&gt;He is the author of several best selling .NET and Win32 programming books including:   The Applied Microsoft .NET Framework Programming in C# Collection Applied Microsoft .NET Framework Programming Applied Microsoft .NET Framework Programming in Microsoft Visual Basic .NET Programming Applications for Microsoft Windows (formerly Advanced Windows). Programming Server-Side Applications for Microsoft Windows In addition, Jeff has also contributed to many other books including: Programming Microsoft Visual Basic .NET (Core Reference), .NET Framework Standard Library Annotated Reference, Vol. 1: System, System.Collections, System.IO, System.Diagnostics, System.Globalization, System.Security, System.Text, System.Threading Microsoft .NET Framework 1.1 Class Library Reference Volumes 1-4: System. Jeffrey is also a contributing editor to MSDN Magazine where he authors the .NET column and has written many feature articles. &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;一点花絮：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;《CLR via C#》的第一版名为《Applied Microsoft .NET Framework Programming》，其修订版之中文版由李建忠译，本来由李建忠接着翻译第二版即《CLR via C#》是顺理成章之事，可人算不如天算，&lt;a href="http://www.lijianzhong.com/?p=6"&gt;李建忠在这里道出了其中原由&lt;/a&gt;。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;现在很多人掰着字典、点着金山词霸在译书！以前在电视上看过陆谷孙先生的讲演，说以前中国人对文字是很敬畏的，曾有“敬惜字纸”的条幅……人心不古，其奈也何？&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;为了表示对《CLR via C#》作者Jeffrey Richter的尊重，期待着该书的影印版……实在不行，就请有到国外出差的朋友给捎一本罢^_^&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+Waiting+for+CLR+via+C%23......&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!338.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!338.entry</guid><pubDate>Wed, 28 Mar 2007 05:47:01 GMT</pubDate><slash:comments>2</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!338/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!338.entry#comment</wfw:comment><dcterms:modified>2007-03-28T05:47:45Z</dcterms:modified></item><item><title>关于DataSet对象</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!276.entry</link><description>&lt;div&gt;1、ADO.NET中的DataSet对象与DataReader对象的关系有点类似于处理XML的DOM与SAX的关系。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;2、DataSet确实是个好东西，解决了两大问题：&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;2.1 由于DataSet的非连接性，使得SQL Server对同时打开的连接数不得多于2000的限制的压力减轻了许多，因为数据可以在DataSet中处理，打开的连接可以迅速关闭，由此大大减轻对数据库的压力。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;2.2 由于DataSet可以序列化为XML，使得DataSet可以在应用程序的各层之间进行传输，由此可以解决LevenSite Server的一大难题：客户端软件对数据库的直接连接。这样一来，LevenSite Server客户端软件与服务器之间可以使用HTTP协议，通过传输XML化的DataSet来实现。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;天何言哉。四时行焉，百物生焉，天何言哉？&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+%e5%85%b3%e4%ba%8eDataSet%e5%af%b9%e8%b1%a1&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!276.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!276.entry</guid><pubDate>Tue, 05 Dec 2006 15:10:49 GMT</pubDate><slash:comments>4</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!276/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!276.entry#comment</wfw:comment><dcterms:modified>2006-12-05T15:10:49Z</dcterms:modified></item><item><title>关于数据服务层及数据访问技术</title><link>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!275.entry</link><description>&lt;div&gt;今天花了一天的时间翻译了Dan Fox（注意，不是Dan Box！）的一篇文章《&lt;a href="http://www.levensoft.com/web/show_col.asp?cid=39&amp;amp;did=31"&gt;设计一个有效的数据访问体系结构&lt;/a&gt;》。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;作者在文中讨论了在设计数据访问应用程序时需要面对的两个设计决策：如何表示数据服务的外部接口，以及如何实现其内部接口。这些问题也是设计LevenSite Server新版本时需要着重考虑的问题。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;关于第一个问题，设计定制类可能成本太高，而数据阅读器又不合适，可选方案就是DataSet对象，由于DataSet对象可以被序列化，所以非常适合作为数据服务的外部接口。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;关于第二个问题，由于LevenSite Server不可能一直绑定于SQL Server，而且由于数据工厂方式高度的代码抽象，故考虑利用数据工厂方式实现其内部接口。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;数据工厂方式涉及到一个称为抽象工厂模式的设计模式，所以需要再仔细研究一下设计模式问题。GoF的《Design Patterns》真可以说是软件设计上的杰出贡献，哎！&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Microsoft的数据访问方式，经历了DB Library，DAO，ODBC，OLE DB，ADO，一直到ADO.NET，几乎为Microsoft多年研发数据访问技术的集大成之作：既有OLE DB的consumer/provider的概念，又有ADO的易用性；既有高效的连接对象DataReader，又有数据库的内存映像的非连接对象DataSet；既可以访问各种关系型数据（tabular data），又可以读写结构化的XML数据；既可以对数据表（DataTable）进行操作，又可以序列化为XML在各层间进行传输。TNND，功能已足够强大了！&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;慢，据说M$又在鼓捣新的东西，有可能会在ADO.NET中加入Factory之类的模式。关于用Abstract Factory Pattern来解决ADO.NET中的窄域与宽域提供者的问题，有很多人写了文章。Microsoft不可能老是让人说自己在provider上的两张皮的做法。&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-1537263819930693984&amp;page=RSS%3a+%e5%85%b3%e4%ba%8e%e6%95%b0%e6%8d%ae%e6%9c%8d%e5%8a%a1%e5%b1%82%e5%8f%8a%e6%95%b0%e6%8d%ae%e8%ae%bf%e9%97%ae%e6%8a%80%e6%9c%af&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=prowyh.spaces.live.com&amp;amp;GT1=prowyh"&gt;</description><comments>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!275.entry#comment</comments><guid isPermaLink="true">http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!275.entry</guid><pubDate>Tue, 05 Dec 2006 14:57:18 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!275/comments/feed.rss</wfw:commentRss><wfw:comment>http://prowyh.spaces.live.com/Blog/cns!EAAA8AB356F88EA0!275.entry#comment</wfw:comment><dcterms:modified>2006-12-06T02:08:49Z</dcterms:modified></item></channel></rss>