<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_Dunnice</title><subtitle type="text">且行且珍惜</subtitle><id>http://feed.cnblogs.com/blog/u/24020/rss</id><updated>2012-04-11T07:26:23Z</updated><author><name>dunnice</name><uri>http://www.cnblogs.com/dunnice/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dunnice/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/24020/rss"/><entry><id>http://www.cnblogs.com/dunnice/archive/2012/04/09/2439316.html</id><title type="text">.NET基础扩展系列-事件的实现原理</title><summary type="text">CLR VIA C#这本书中, 写到了事件的实现原理, CLR是使用委托字段来实现事件的:// 1. A PRIVATE delegate field that is initialized to null static EventHandler&lt;EventArgs&gt; NewMail = null;// 2. A PUBLIC add_Xxx method (where Xxx is the Event name) // Allows methods to register interest in the event. static void add_NewMail(EventHa</summary><published>2012-04-09T09:41:00Z</published><updated>2012-04-09T09:41:00Z</updated><author><name>dunnice</name><uri>http://www.cnblogs.com/dunnice/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dunnice/archive/2012/04/09/2439316.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dunnice/archive/2012/04/09/2439316.html"/><content type="html">&lt;p&gt;CLR VIA C#这本书中, 写到了事件的实现原理, CLR是使用委托字段来实现事件的:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 1. A PRIVATE delegate field that is initialized to null &lt;/span&gt;&lt;br/&gt;&lt;span style="color: #0000ff;"&gt;static&lt;/span&gt; EventHandler&amp;lt;EventArgs&amp;gt; NewMail = &lt;span style="color: #0000ff;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 2. A PUBLIC add_Xxx method (where Xxx is the Event name) &lt;br/&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Allows methods to register interest in the event. &lt;/span&gt;&lt;br/&gt;&lt;span style="color: #0000ff;"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;void&lt;/span&gt; add_NewMail(EventHandler&amp;lt;EventArgs&amp;gt;&lt;span style="color: #000000;"&gt; value)&lt;br/&gt;{&lt;br/&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;    //&lt;/span&gt;&lt;span style="color: #008000;"&gt; The loop and the call to CompareExchange is all just a fancy way &lt;br/&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;    //&lt;/span&gt;&lt;span style="color: #008000;"&gt; of adding a delegate to the event in a thread-safe way &lt;/span&gt;&lt;br/&gt;    EventHandler&amp;lt;EventArgs&amp;gt;&lt;span style="color: #000000;"&gt; prevHandler;&lt;br/&gt;    EventHandler&lt;/span&gt;&amp;lt;EventArgs&amp;gt; tmp =&lt;span style="color: #000000;"&gt; NewMail;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;    do&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br/&gt;    {&lt;br/&gt;        prevHandler &lt;/span&gt;=&lt;span style="color: #000000;"&gt; tmp;&lt;br/&gt;        EventHandler&lt;/span&gt;&amp;lt;EventArgs&amp;gt; newHandler = &lt;span style="color: #000000;"&gt;(EventHandler&lt;/span&gt;&amp;lt;EventArgs&amp;gt;&lt;span style="color: #000000;"&gt;)Delegate.Combine(prevHandler, value); &lt;br/&gt;        tmp &lt;/span&gt;= Interlocked.CompareExchange&amp;lt;EventHandler&amp;lt;EventArgs&amp;gt;&amp;gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;ref&lt;/span&gt;&lt;span style="color: #000000;"&gt; NewMail, newHandler, prevHandler);&lt;br/&gt;    } &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;while&lt;/span&gt; (tmp !=&lt;span style="color: #000000;"&gt; prevHandler);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; 3. A PUBLIC remove_Xxx method (where Xxx is the Event name) &lt;br/&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Allows methods to unregister interest in the event. &lt;/span&gt;&lt;br/&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;void&lt;/span&gt; remove_NewMail(EventHandler&amp;lt;EventArgs&amp;gt;&lt;span style="color: #000000;"&gt; value)&lt;br/&gt;{&lt;br/&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;    //&lt;/span&gt;&lt;span style="color: #008000;"&gt; The loop and the call to CompareExchange is all just a fancy way &lt;br/&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;    //&lt;/span&gt;&lt;span style="color: #008000;"&gt; of removing a delegate from the event in a thread-safe way &lt;/span&gt;&lt;br/&gt;    EventHandler&amp;lt;EventArgs&amp;gt;&lt;span style="color: #000000;"&gt; prevHandler; &lt;br/&gt;    EventHandler&lt;/span&gt;&amp;lt;EventArgs&amp;gt; tmp =&lt;span style="color: #000000;"&gt; NewMail;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;    do&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br/&gt;    {&lt;br/&gt;        prevHandler &lt;/span&gt;=&lt;span style="color: #000000;"&gt; tmp;&lt;br/&gt;        EventHandler&lt;/span&gt;&amp;lt;EventArgs&amp;gt; newHandler = &lt;span style="color: #000000;"&gt;(EventHandler&lt;/span&gt;&amp;lt;EventArgs&amp;gt;&lt;span style="color: #000000;"&gt;)Delegate.Remove(prevHandler, value);&lt;br/&gt;        tmp&lt;/span&gt;= Interlocked.CompareExchange&amp;lt;EventHandler&amp;lt;EventArgs&amp;gt;&amp;gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;ref&lt;/span&gt;&lt;span style="color: #000000;"&gt; NewMail, newHandler, prevHandler);&lt;br/&gt;    } &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;while&lt;/span&gt; (tmp!=&lt;span style="color: #000000;"&gt; prevHandler);&lt;br/&gt;}&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;但是里面tmp = Interlocked.CompareExchange&amp;lt;EventHandler&amp;lt;EventArgs&amp;gt;&amp;gt;(ref NewMail, newHandler, prevHandler);&lt;/p&gt;&lt;p&gt;这一句是用于赋值的, 为什么不采用Interlocked.Exchange方法直接赋值呢? 而要采取这么迂回的方式, 使用CompareExchange和(newMail != prevHandler)来组合判断.&amp;nbsp;&lt;a href="http://www.cnblogs.com/dunnice/admin/"&gt;&lt;br /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;在单线程的情况下, 这两种情况的效果是一样的.&amp;nbsp;&lt;/p&gt;&lt;p&gt;而在用多线程并发的情况下, 就会发现为什么只能用CompareExchange.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;假设有两个线程A和B, 同时在添加实现响应函数, 也就是调用add_NewMail函数.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;假设事件NewMail初始化时没有时间响应函数, A需要添加一个FunctionA响应函数, B需要添加一个FunctionB函数.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;第一步：线程A先开始执行,执行完下面这一句后, 停止执行:EventHandler&amp;lt;EventArgs&amp;gt; newHandler =(EventHandler&amp;lt;EventArgs&amp;gt;)Delegate.Combine(prevHandler, value);&amp;nbsp;&lt;/p&gt;&lt;p&gt;此时的NewMail 为null,&amp;nbsp;newHandler 为FunctionA. 线程A停止.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;第二步：线程B开始执行,将整个函数执行完,&amp;nbsp;&lt;/p&gt;&lt;p&gt;此时NewMail 为FunctionB&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;第三步：线程A继续执行, 会执行这一句:&amp;nbsp;tmp = Interlocked.CompareExchange&amp;lt;EventHandler&amp;lt;EventArgs&amp;gt;&amp;gt;(ref NewMail, newHandler, prevHandler);&lt;/p&gt;&lt;p&gt;由于此时NewMail =FunctionB , 所以tmp 会=FunctionB ,&lt;/p&gt;&lt;p&gt;但由于prevHandler=&amp;nbsp;FunctionA, 所以NewMail!=prevHandler, 所以NewMail保持值不变.&amp;nbsp;&lt;/p&gt;&lt;p&gt;往下执行while (tmp != prevHandler)的判断, 就会发现tmp!=prevHandler, 就会继续循环, 直到&lt;span style="background-color: #ffff00;"&gt;NewMail 和prevHandler&amp;nbsp;值一样了,才会退出循环.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;这样看就比较清楚, 为什么不能用Exchange了, 如果使用Exchange,那么在第三步的时候, 就会直接执行赋值, 将NewMail设置为FunctionA,那么FucntionB就不会出现在时间相应函数的委托链表中.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;为什么CompareExchange, 就可以呢?&lt;/p&gt;&lt;p&gt;其实是用CompareExchange去验证线程并发控制的一个最根本的原则: &lt;span style="background-color: #ffff00;"&gt;如果一个操作要被看做是不可打断的, 那么从开始到完成的真个环节中, 操作的环境不能改变.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="background-color: #ffffff;"&gt;我们随使用CompareExchange, 就可以验证NewMail 是不是我们最开始操作时候的prevHandler, 如果不是, 说明操作的基本环境已经改变, 这次操作就是无效的.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="background-color: #ffffff;"&gt;这种方式, 可以在不适用lock的情况下, 实现并发控制, 相当精妙.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dunnice/aggbug/2439316.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dunnice/archive/2012/04/09/2439316.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dunnice/archive/2012/03/19/2406458.html</id><title type="text">.NET基础扩展系列-如何获取事件的响应函数列表</title><summary type="text">很多对象实现了IDispose接口的, 例如Socket对象. 在使用后, 需要及时调用Dispose()方法销毁.但是如果对象上的事件注册了事件响应函数, 那么就必须等待事件响应函数所在的对象回收以后, 它才能回收, 这个很容易导致程序出问题.所以比较理想的方案是在调用Dispose()之前, 把时间的事件响应函数注销掉. 这个就ok了. 但是对象的事件响应函数可以添加多个, 而且一个事件可能在若干个对象中被注册了响应函数, 如何获取调用函数的列表呢, 然后住校呢. &lt;CLR VIA C#&gt;的事件一章, 详细讲解了.net的事件是通过字段+方法来实现的. 也就是说, 事件会被翻译</summary><published>2012-03-19T09:57:00Z</published><updated>2012-03-19T09:57:00Z</updated><author><name>dunnice</name><uri>http://www.cnblogs.com/dunnice/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dunnice/archive/2012/03/19/2406458.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dunnice/archive/2012/03/19/2406458.html"/><content type="html">&lt;p&gt;&amp;nbsp; &amp;nbsp; 很多对象实现了IDispose接口的, 例如Socket对象. 在使用后, 需要及时调用Dispose()方法销毁.&lt;/p&gt;&lt;p&gt;但是如果对象上的事件注册了事件响应函数, 那么就必须等待事件响应函数所在的对象回收以后, 它才能回收, 这个很容易导致程序出问题.&lt;/p&gt;&lt;p&gt;所以比较理想的方案是在调用Dispose()之前, 把时间的事件响应函数注销掉.&amp;nbsp; 这个就ok了.&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; 但是对象的事件响应函数可以添加多个, 而且一个事件可能在若干个对象中被注册了响应函数, 如何获取调用函数的列表呢, 然后住校呢.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;CLR VIA C#&amp;gt;的事件一章, 详细讲解了.net的事件是通过字段+方法来实现的. 也就是说, 事件会被翻译成一个对应的委托私有字段.&lt;/p&gt;&lt;p&gt;那么我们如果能够获取到委托的值, 就能获取到响应函数列表了.&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #0000ff;"&gt;static&lt;/span&gt; EventHandler&amp;lt;EventArgs&amp;gt; GetEventHandler(&lt;span style="color: #0000ff;"&gt;object&lt;/span&gt; classInstance, &lt;span style="color: #0000ff;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; eventName)&lt;br/&gt;{&lt;br/&gt;    Type classType &lt;/span&gt;=&lt;span style="color: #000000;"&gt; classInstance.GetType();&lt;br/&gt;    FieldInfo eventField &lt;/span&gt;= classType.GetField(eventName, BindingFlags.GetField | BindingFlags.NonPublic |&lt;span style="color: #000000;"&gt; BindingFlags.Instance);&lt;br/&gt;&lt;br/&gt;    EventHandler&lt;/span&gt;&amp;lt;EventArgs&amp;gt; eventDelegate = (EventHandler&amp;lt;EventArgs&amp;gt;&lt;span style="color: #000000;"&gt;)eventField.GetValue(classInstance);&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; eventDelegate will be null if no listeners are attached to the event&lt;/span&gt;&lt;br/&gt;    &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; (eventDelegate == &lt;span style="color: #0000ff;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;br/&gt;    {&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; eventDelegate;&lt;br/&gt;}&lt;/span&gt;&lt;/div&gt;&lt;p&gt;这段代码就是获取事件对应委托的.&lt;/p&gt;&lt;p&gt;获取到委托以后, 调用委托的GetInvocationList()方法, 就可以获得响应函数列表了, 然后强制转换成对应的事件类型, 然后对事件执行-=操作, 就可以了. &lt;br /&gt;代码如下:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;Delegate[] dgs =&lt;span style="color: #000000;"&gt; eventDelegate.GetInvocationList(); &lt;br/&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;foreach&lt;/span&gt; (Delegate dg &lt;span style="color: #0000ff;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt; dgs) &lt;br/&gt;{ &lt;br /&gt;    EventHandler&lt;/span&gt;&amp;lt;EventArgs&amp;gt; eh = (dg &lt;span style="color: #0000ff;"&gt;as&lt;/span&gt; EventHandler&amp;lt;EventArgs&amp;gt;&lt;span style="color: #000000;"&gt;); &lt;br/&gt;    host.TestEvent &lt;/span&gt;-=&lt;span style="color: #000000;"&gt; eh; &lt;br/&gt;}&lt;/span&gt;&lt;/div&gt;&lt;p&gt;不过需要注意的是:&lt;strong&gt; .net中, 还提供属性事件: 也即是会被.net翻译成属性的事件, 具体可以看MSDN中对于事件的介绍中, 专门有一节介绍了属性事件. &lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;一般属性事件适用于WinForm程序. &lt;/strong&gt;&lt;/p&gt;&lt;p&gt;获取属性事件的响应函数列表的过程类型, 只是把:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;FieldInfo eventField = classType.GetField(eventName, BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);&lt;/div&gt;&lt;p&gt;替换成:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;PropertyInfo propertyInfo = (&lt;span style="color: #0000ff;"&gt;typeof&lt;/span&gt;(EventHost)).GetProperty(eventNameBindingFlags.Instance | BindingFlags.NonPublic ); &lt;/div&gt;&lt;p&gt;其实就是从获取字段信息变成获取属性信息.&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dunnice/aggbug/2406458.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dunnice/archive/2012/03/19/2406458.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dunnice/archive/2012/02/19/2358213.html</id><title type="text">你当下的决定, 可能能够影响你未来5年的幸福. 所以, 最好考虑一下5年后的你最这件事情的看法.</title><summary type="text">你当下的决定, 可能能够影响你未来5年的幸福. 所以, 最好考虑一下5年后的你最这件事情的看法.</summary><published>2012-02-19T07:30:00Z</published><updated>2012-02-19T07:30:00Z</updated><author><name>dunnice</name><uri>http://www.cnblogs.com/dunnice/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dunnice/archive/2012/02/19/2358213.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dunnice/archive/2012/02/19/2358213.html"/><content type="html">你当下的决定, 可能能够影响你未来5年的幸福. 所以, 最好考虑一下5年后的你最这件事情的看法,无法的事情, 在当时看来无足轻重,但是5年过后, 所能够带来的影响也许是很巨大的.   时间和环境的变化就是那只震翅的蝴蝶, 5年时间, 那只蝴蝶也许就能让你的生活产出巨大的效应, 这让我想起一个很著名的效应: 蝴蝶效应. &lt;img src="http://www.cnblogs.com/dunnice/aggbug/2358213.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dunnice/archive/2012/02/19/2358213.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dunnice/archive/2012/02/17/2356205.html</id><title type="text">字符串生成Hash值后转换成Guid的若干方法和一个重要问题</title><summary type="text">字符串计算成Hash值的代码如下: MD5 md5 = MD5.Create();byte[] data = System.Text.Encoding.Default.GetBytes(str);byte[] md5data = md5.ComputeHash(data);计算出Hash值后,结果是一堆byte, 不方便多个hash值进行比较.由于Hash值计算出来是一个128位的值, 转换成字符...</summary><published>2012-02-17T09:55:00Z</published><updated>2012-02-17T09:55:00Z</updated><author><name>dunnice</name><uri>http://www.cnblogs.com/dunnice/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dunnice/archive/2012/02/17/2356205.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dunnice/archive/2012/02/17/2356205.html"/><content type="html">&lt;p&gt;字符串计算成Hash值的代码如下: &lt;/p&gt;MD5 md5 = MD5.Create();&lt;br/&gt;byte[] data = System.Text.Encoding.Default.GetBytes(str);&lt;br/&gt;byte[] md5data = md5.ComputeHash(data);&amp;nbsp;计算出Hash值后,结果是一堆byte, 不方便多个hash值进行比较.由于Hash值计算出来是一个128位的值, 转换成字符串表达形式就好对比多了,也就是MD5码的字符串形式, 另外由于Guid也是128位的,所以可以用guid来存储这个MD5码.&amp;nbsp;先说一种不正规的MD5生成方法: return new Guid(md5data);请注意: 这种方式生成的Guid和下面几种方式生成的guid的结果是不一样的,并不是说就是错误的, 使用的时候需要注意.  &amp;nbsp;生成Guid有几种方法(这几种方式生成的guid是正确的):一:for (int i = 0; i &amp;amp;lt; md5data.Length; ++i)&lt;br/&gt;{&lt;br/&gt;      str += md5data[i].ToString("x").PadLeft(2, '0');&lt;br/&gt;}&lt;br/&gt;return new Guid(str);&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;font face="Courier New"&gt;二:&lt;/font&gt;&lt;/p&gt;int first4 = byteToInt32(md5data, 0);&lt;br/&gt;short next2 = byteToInt16(md5data, 4);&lt;br/&gt;short next3 = byteToInt16(md5data, 6);&lt;br/&gt;return new Guid(first4, next2, next3, ne);&amp;nbsp;为什么new Guid(md5data)这种方法是错误的呢.因为这种方法调用底层Win32的方法转换字符与byte,而.net与C在字节的高位顺序上是相反的, 所以会出现前16位不一致的情况.导致计算出来的MD5码不正确.&amp;nbsp;后两种方法的思路是先计算出来MD5码,然后生成Guid,这样md5码就不会受到高地位的影响. 但是要注意一个问题: 后两种方法生成的guid, 调用ToByteArray生成的字节数值和md5data是不一样的. 所以我们要注意的是, 我们是使用Guid来存储Md5码,所以要先计算MD5(MD5码的算法是固定的).&amp;nbsp;&lt;img src="http://www.cnblogs.com/dunnice/aggbug/2356205.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dunnice/archive/2012/02/17/2356205.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dunnice/archive/2012/01/01/2309488.html</id><title type="text">告别2011,走进2012,你终于来了.</title><summary type="text">记得去年年初的时候, 在回北京的飞机上, 看了一篇文章, 是一本杂志的新年辞, 什么题目不太记得了, 只记得里面列举了一大堆2011之前没有的东西. 每天生活都在变. 一年前,我还在梦想去华为或者哪家跨国公司, 继续在北京蚁这, 但是这一年,我从北京到了重庆,开始了新的人生; 一年前,重庆的房子还没有那么贵, 贷款利率还不上调,一年后的我们依然没有钱, 望着小房子,感受着自己的卑微; ...</summary><published>2012-01-01T07:32:00Z</published><updated>2012-01-01T07:32:00Z</updated><author><name>dunnice</name><uri>http://www.cnblogs.com/dunnice/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dunnice/archive/2012/01/01/2309488.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dunnice/archive/2012/01/01/2309488.html"/><content type="html">&lt;p&gt;记得去年年初的时候, 在回北京的飞机上, 看了一篇文章, 是一本杂志的新年辞, 什么题目不太记得了, 只记得里面列举了一大堆2011之前没有的东西. &lt;/p&gt;  &lt;p&gt;每天生活都在变. &lt;/p&gt;  &lt;p&gt;一年前,我还在梦想去华为或者哪家跨国公司, 继续在北京蚁这, 但是这一年,我从北京到了重庆,开始了新的人生;&lt;/p&gt;  &lt;p&gt;一年前,重庆的房子还没有那么贵, 贷款利率还不上调,一年后的我们依然没有钱, 望着小房子,感受着自己的卑微;&lt;/p&gt;  &lt;p&gt;一年前,还是一个人,现在,要带着两个人的梦想, 继续前进.&lt;/p&gt;  &lt;p&gt;还有很多…&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;生活在继续…2012,你终于来了.&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dunnice/aggbug/2309488.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dunnice/archive/2012/01/01/2309488.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dunnice/archive/2011/12/26/2301830.html</id><title type="text">正则表达式如何匹配换行符</title><summary type="text">正则表达式中, .通配符是不匹配换行符的. 那么怎样能够匹配换行符号呢, 使用\s就能匹配了, \s 匹配任意的空白符.</summary><published>2011-12-26T03:51:00Z</published><updated>2011-12-26T03:51:00Z</updated><author><name>dunnice</name><uri>http://www.cnblogs.com/dunnice/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dunnice/archive/2011/12/26/2301830.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dunnice/archive/2011/12/26/2301830.html"/><content type="html">&lt;p&gt;正则表达式中, .通配符是不匹配换行符的. 那么怎样能够匹配换行符号呢, &lt;/p&gt;  &lt;p&gt;使用\s就能匹配了, &lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;\s 匹配&lt;font color="#ff0000"&gt;任意&lt;/font&gt;的空白符.&lt;/p&gt;&lt;/blockquote&gt;&lt;img src="http://www.cnblogs.com/dunnice/aggbug/2301830.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dunnice/archive/2011/12/26/2301830.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dunnice/archive/2011/08/13/2137439.html</id><title type="text">log4net的配置</title><summary type="text">log4net在开始使用的配置完config文件的时候, 需要记住一定要在程序中关联配置文件, 这一步很容易忽略和遗忘.配置的方法入下:在AssemblyInfo.cs文件中, 添加[assembly: log4net.Config.XmlConfiguratorAttribute(Watch = true)]如果不添加这一句, 在调用log添加日志的时候, 不会报错但是也无法保存, 所以这点很重要.</summary><published>2011-08-13T09:47:00Z</published><updated>2011-08-13T09:47:00Z</updated><author><name>dunnice</name><uri>http://www.cnblogs.com/dunnice/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dunnice/archive/2011/08/13/2137439.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dunnice/archive/2011/08/13/2137439.html"/><content type="html">&lt;p&gt;log4net在开始使用的配置完config文件的时候, 需要记住一定要在程序中关联配置文件, 这一步很容易忽略和遗忘.&lt;/p&gt;&lt;p&gt;配置的方法入下:&lt;/p&gt;&lt;p&gt;在AssemblyInfo.cs文件中, 添加[assembly: log4net.Config.XmlConfiguratorAttribute(Watch = true)]&lt;/p&gt;&lt;p&gt;如果不添加这一句, 在调用log添加日志的时候, 不会报错但是也无法保存, 所以这点很重要.&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dunnice/aggbug/2137439.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dunnice/archive/2011/08/13/2137439.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dunnice/archive/2011/08/13/2136861.html</id><title type="text">关于单元测试</title><summary type="text">关于单元测试:我们为什么要做单元测试?引入单元测试是很简单的，因为它本身就充满了乐趣。然而在项目交付的时候，我们给客户和最终用户的仍然是产品代码，而不包含单元测试的代码；因此，我们必须对单元测试的目的有个充分的认识。首先也是最重要的，使用单元测试是为了使你的工作——以及你队友的工作——完成得更加轻松。是不是编写单元测试会增加编码的时间, 是不是在浪费时间?如果你仍然认为在编写产品代码的时候，还是没有时间编写测试代码，那么请先考虑下面这些问题： 1. 对于所编写的代码，你在调试上面花了多少时间？ 2. 对于以前你自认为正确的代码，而实际上这些代码却存在重大的bug，你花了多少时间在重新确认这些代</summary><published>2011-08-12T16:08:00Z</published><updated>2011-08-12T16:08:00Z</updated><author><name>dunnice</name><uri>http://www.cnblogs.com/dunnice/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dunnice/archive/2011/08/13/2136861.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dunnice/archive/2011/08/13/2136861.html"/><content type="html">&lt;p&gt;&lt;span style="font-family: 宋体; font-size: 13px;"&gt;关于单元测试:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 宋体; font-size: 13px;"&gt;我们为什么要做单元测试?&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 黑体; font-size: 13px;"&gt;引入单元测试是很简单的，因为它本身就充满了乐趣。然而在项目交付的时候，我们给客户和最终用户的仍然是产品代码，而不包含单元测试的代码；因此，我们必须对单元测试的目的有个充分的认识。首先也是最重要的，使用单元测试是为了使你的工作&amp;mdash;&amp;mdash;以及你队友的工作&amp;mdash;&amp;mdash;完成得更加轻松。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 宋体; font-size: 13px;"&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 宋体; font-size: 13px;"&gt;是不是编写单元测试会增加编码的时间, 是不是在浪费时间?&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 黑体; font-size: 13px;"&gt;如果你仍然认为在编写产品代码的时候，还是没有时间编写测试代码，那么请先考虑下面这些问题：&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 黑体; font-size: 13px;"&gt;    1.  对于所编写的代码，你在调试上面花了多少时间？&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 黑体; font-size: 13px;"&gt;    2.  对于以前你自认为正确的代码，而实际上这些代码却存在重大的bug，你花了多少时间在重新确认这些代码上面？&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 黑体; font-size: 13px;"&gt;    3.  对于一个别人报告的bug，你花了多少时间才找出导致这个bug 的源码位置？&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 黑体; font-size: 13px;"&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 宋体; font-size: 13px;"&gt;单元测试的优点?&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-family: 黑体; font-size: 13px;"&gt;及时发现问题&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 黑体; font-size: 13px;"&gt;&lt;span style="font-family: '微软雅黑','sans-serif';"&gt;从长远看来，使用&amp;ldquo;立即测试模型&amp;rdquo;的代价比&amp;ldquo;延后测试模型&amp;rdquo;的代价要低。在你编写实现代码的时候，同时编写独立的测试代码，在项目最后就可以避免出现做了无用功的问题；代码中的&lt;/span&gt;bug &lt;span style="font-family: '微软雅黑','sans-serif';"&gt;也会更少，因为你所依赖的都是已经通过测试的代码。于是，通过在开发过程中多花一点时间在编写单元测试上面，你就可以最小化在项目后期花费大量时间的风险。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dunnice/aggbug/2136861.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dunnice/archive/2011/08/13/2136861.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dunnice/archive/2011/07/17/2108622.html</id><title type="text">C#根据字符串生成唯一的数字</title><summary type="text">C#根据字符串生成唯一的 19位数字</summary><published>2011-07-17T03:13:00Z</published><updated>2011-07-17T03:13:00Z</updated><author><name>dunnice</name><uri>http://www.cnblogs.com/dunnice/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dunnice/archive/2011/07/17/2108622.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dunnice/archive/2011/07/17/2108622.html"/><content type="html">&lt;p&gt;  &amp;nbsp;&amp;nbsp;&amp;nbsp; 根据字符串生成唯一的数字标识, 一般我们都会采用GUID, 根据字符串计算MD5, 计算出来的MD5码就是一个GUID. &lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 但是GUID太长了, 是一个128位的数字, 在存储的时候, 会很占地方, 考虑能不能生成一个短一点的数字, 比如32为的数字, 搜了搜, 有人给出了这样的方法.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; : 我们可以将一个标准的GUID &lt;em&gt;21726045-e8f7-4b09-abd8-4bcc926e9e28&lt;/em&gt; 转换成短的字符串 &lt;em&gt;3c4ebc5f5f2c4edc&lt;/em&gt;&lt;/p&gt;&lt;p&gt;下面的方法会生成一个短的字符串，并且这个字符串是唯一的。重复1亿次都不会出现重复的，它也是依照GUID的唯一性来生成这个字符串的。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;div&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;GenerateStringID()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;long&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;i&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;1&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;foreach&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;byte&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;b&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;in&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;Guid.NewGuid().ToByteArray())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;i&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;*=&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;((&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)b&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;1&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;.Format(&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;{0:x}&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;,&amp;nbsp;i&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;-&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;DateTime.Now.Ticks);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;如果想生成一个数字序列而不是字符串，你将会获得一个19位长的序列。下面的方法会把GUID转换为Int64的数字序列。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;div&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;long&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;GenerateIntID()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;byte&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;[]&amp;nbsp;buffer&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;Guid.NewGuid().ToByteArray();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;nbsp;BitConverter.ToInt64(buffer,&amp;nbsp;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;0&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;看起来这个方法是可行的, 但是暂时没有找到严谨的数据论证, 可以保证多高的不冲突性能. 毕竟是做key值, 如果有一个重复, 程序就挂了.&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dunnice/aggbug/2108622.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dunnice/archive/2011/07/17/2108622.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dunnice/archive/2011/05/24/2055068.html</id><title type="text">三点定面的算法实现</title><summary type="text">三点定面 算法 C# 实现</summary><published>2011-05-24T02:05:00Z</published><updated>2011-05-24T02:05:00Z</updated><author><name>dunnice</name><uri>http://www.cnblogs.com/dunnice/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dunnice/archive/2011/05/24/2055068.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dunnice/archive/2011/05/24/2055068.html"/><content type="html">&lt;a href="http://files.cnblogs.com/dunnice/GeometryHelper.txt"&gt;/Files/dunnice/GeometryHelper.txt&lt;/a&gt;&lt;div&gt;在做Gis的时候, 遇到一个通过三点定面的问题,在求解面公式的时候, 没有找到简单的第三方控件.就自己写了一个简单的方法. &lt;br /&gt;&lt;br /&gt;三点定面公式:&lt;br /&gt;Ax + By + Cz + D =0&lt;br /&gt;x: x轴值&lt;br /&gt;y: y轴值&lt;br /&gt;z: z轴值&lt;br /&gt;&lt;br /&gt;以下是数值版的逻辑推理版本:&lt;br /&gt;已知三点P（1，-1，1） Q（2，4，6） S（1，0，3)&lt;br /&gt;&lt;br /&gt;求出两个向量PQ（1，5，5）和PS（0，1，2）两条线&lt;br /&gt;&lt;br /&gt;三点确定一个平面&lt;br /&gt;设平面上任意一点T的坐标为（x,y,z）&lt;br /&gt;则PT可以表示成aPQ+bPS&amp;nbsp; 其中a,b为任意常数&lt;br /&gt;即(x-1,y+1,z-1)=a(1,5,5)+b(0,1,2)=(a,5a+b,5a+2b)&lt;br /&gt;所以&lt;br /&gt;x-1=a&lt;br /&gt;y+1=5a+b&lt;br /&gt;z-1=5a+2b&lt;br /&gt;把第一个式子代入第二个式子得&lt;br /&gt;y+1=5(x-1)+b&lt;br /&gt;b=y+1-5x+5=y-5x+6&lt;br /&gt;代入第三个式子&lt;br /&gt;z-1=5(x-1)+2(y-5x+6)&lt;br /&gt;整理得&lt;br /&gt;5x-2y+z-8=0&lt;br /&gt;则&lt;br /&gt;该平面的公式为&lt;br /&gt;5x-2y+z-8=0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;以下是纯逻辑推理版本:&lt;br /&gt;三个点:&lt;br /&gt;(x1, y1, z1) (x2, y2, z2) (x2, y3, z3)&lt;br /&gt;&lt;br /&gt;向量坐标的基准点为(x1, y1, z1):&lt;br /&gt;PQ(x2-x1, y2-y1, z2-z1)&amp;nbsp; =&amp;gt;&amp;nbsp; PQ(x4, y4, z4)&lt;br /&gt;PS(x3-x1, y3-y1, z3-z1)&amp;nbsp; =&amp;gt;&amp;nbsp; PS(x5, y5, z5)&lt;br /&gt;&lt;br /&gt;对于平面中人和一个点(x, y, z):&lt;br /&gt;(x-x1, y-y1, z-z1) = a*PQ + b*PS =&amp;gt; a*(x4, y4, z4) + b*(x5, y5, z5)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;gt; (a*x4+b*x5, a*y4+b*y5, a*z4+b*z5)&lt;br /&gt;&lt;br /&gt;所以:&lt;br /&gt;x-x1 = a*x4 + b*x5&lt;br /&gt;y-y1 = a*y4 + b*y5&lt;br /&gt;z-z1 = a*z4 + b*z5&lt;br /&gt;&lt;br /&gt;有第一个公式得出:&lt;br /&gt;a = (x - x1 - b*x5)/x4 &lt;br /&gt;&amp;nbsp; =&amp;gt; x/x4 - x1/x4 - b*x5/x4&lt;br /&gt;&lt;br /&gt;将a的转换公式代入第二个公式:&lt;br /&gt;y-y1 = (x/x4 - x1/x4 - b*x5/x4)*y4 + b*y5 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;gt; x*y4/x4 - x1*y4/x4 - b*x5*y4/x4 + b*y5&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;gt; x*y4/x4 - x1*y4/x4 + b*(y5 - x5*y4/x4)&lt;br /&gt;得出:&lt;br /&gt;b = (y - y1 - x*y4/x4 + x1*y4/x4)/(y5 - x5*y4/x4) &lt;br /&gt;&lt;br /&gt;将a的转换公式代入第三个公式:&lt;br /&gt;z-z1 = (x/x4 - x1/x4 - b*x5/x4)*z4 + b*z5&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;gt; x*z4/x4 - x1*z4/x4 - b*x5*z4/x4 + b*z5&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;gt; x*z4/x4 - x1*z4/x4 + b*(z5 - x5*z4/x4)&lt;br /&gt;&lt;br /&gt;将b的转换公式代入第三个公式得到:&lt;br /&gt;z-z1 = x*z4/x4 - x1*z4/x4&amp;nbsp; + ((y - y1 - x*y4/x4 + x1*y4/x4)/(y5 - x5*y4/x4))*(z5 - x5*z4/x4)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;gt; x*z4/x4 - x1*z4/x4&amp;nbsp; + ((y - y1 - x*y4/x4 + x1*y4/x4)/(y5 - x5*y4/x4))*(z5 - x5*z4/x4)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;gt; x*z4/x4 - x1*z4/x4&amp;nbsp; + ((y - y1 - x*y4/x4 + x1*y4/x4)/(y5 - x5*y4/x4))*(z5 - x5*z4/x4)&lt;br /&gt;&lt;br /&gt;设(y5 - x5*y4/x4) 为 k&lt;br /&gt;设(z5 - x5*z4/x4) 为 j&lt;br /&gt;设(x1*y4/x4- y1)&amp;nbsp; 为 l&lt;br /&gt;&lt;br /&gt;z-z1 =&amp;gt; x*z4/x4 - x1*z4/x4&amp;nbsp; + ((y&amp;nbsp; - x*y4/x4 + l)/k)*j &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;gt; x*z4/x4 - x1*z4/x4&amp;nbsp; + y*j/k - x*y4*j/(x4*k) + l*j/k&lt;br /&gt;&lt;br /&gt;所以平面公式为:&lt;br /&gt;-x*z4/x4 + x1*z4/x4&amp;nbsp; - y*j/k + x*y4*j/(x4*k) - l*j/k + z - z1 = 0&lt;br /&gt;&lt;br /&gt;将常量放到公式末尾:&lt;br /&gt;x*(y4*j/(x4*k) - *z4/x4) - y*j/k + z + (x1*z4/x4 - l*j/k - z1) = 0 &lt;br /&gt;&lt;br /&gt;所以&lt;br /&gt;A = j*y4/(x4*k) - z4/x4&lt;br /&gt;B = -j/k&lt;br /&gt;C = 1&lt;br /&gt;D = x1*z4/x4 - l*j/k - z1&lt;br /&gt;&lt;br /&gt;对应的程序就非常简单了. 自己写就行了.&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;后来才发现, 上面的方法, 在求任何两个点的x坐标和y坐标都不相同的时候, 是可以的, 但是如果有相同的情况, 那就处理不了了. &lt;/div&gt;&lt;div&gt;所以还是需要采用线性代数的方式进行求解. &lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;Matrix类型如下:&lt;/div&gt;&lt;div&gt;&lt;a href="http://files.cnblogs.com/dunnice/Matrix.txt"&gt;/Files/dunnice/Matrix.txt&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;具体求解的代码如下:&lt;/div&gt;&lt;div&gt;&lt;a href="http://files.cnblogs.com/dunnice/GeometryHelper.txt"&gt;/Files/dunnice/GeometryHelper.txt&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;这个确实好使.&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt; &lt;img src="http://www.cnblogs.com/dunnice/aggbug/2055068.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dunnice/archive/2011/05/24/2055068.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
