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

<channel>
	<title>Unlock Particle &#187; C-Sharp</title>
	<atom:link href="http://catouse.com/category/c-sharp-coding/feed" rel="self" type="application/rss+xml" />
	<link>http://catouse.com</link>
	<description>Game &#38; Graphics Programing, AI &#38; Algorithm Exercises</description>
	<lastBuildDate>Thu, 17 Mar 2011 09:13:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>到底有多少条路?</title>
		<link>http://catouse.com/c-sharp-coding/how-many-ways.html</link>
		<comments>http://catouse.com/c-sharp-coding/how-many-ways.html#comments</comments>
		<pubDate>Sun, 02 May 2010 19:40:09 +0000</pubDate>
		<dc:creator>Catouse</dc:creator>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[C-Sharp]]></category>
		<category><![CDATA[Math]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[动态规划]]></category>
		<category><![CDATA[归纳法]]></category>
		<category><![CDATA[杨辉三角]]></category>
		<category><![CDATA[谜题]]></category>
		<category><![CDATA[路径]]></category>
		<category><![CDATA[递推]]></category>

		<guid isPermaLink="false">http://catouse.com/c-sharp-%e7%bc%96%e7%a8%8b/%e5%88%b0%e5%ba%95%e6%9c%89%e5%a4%9a%e5%b0%91%e6%9d%a1%e8%b7%af.html</guid>
		<description><![CDATA[今天(已经是昨天了)又翻了翻《啊哈,灵机一动》(马丁·加德纳著),有个排列组合的谜题是复杂的路.要求就是寻找在一个错综复杂的路径图里面从一个节点到另一个节点的所有可行路径数目.已规定每次我只能选择向右或者向上移动一个位置. 比如上图是一个棋盘形式的路径图,比较容易找规律,如果我愿意花一个钟头的时间的话,我可以把所有路径列举出来,如果顺利的话,我想可以给我更少的时间.我小时候总是为自己能很快而准确的列举找到答案而洋洋得意.我还记得小时候寻找一个笼子里面兔子和鸡的合适数目,我忙碌的在草稿纸上列举所有兔子的腿数和鸡的腿数. 虽然我知道很少有人愿意按照上面的方法去得到答案,但是如果去做了,我肯定能从中找到规律.不过下面从一个格子开始分析,这样也许是一个很不错的尝试.当我被迫要打开柜子所有抽屉找到所有装了纽扣的抽屉时,从第一个抽屉开始,是个明智的决定,这样不至于后来一团糟,想象一下,当你最后都不知道打开哪些抽屉而又不得不再次打开验证时是多么的令人沮丧. 显而易见,在一个格子里面,从左下角到右上角有两种路径.如上图A→C→B和A→D→B. 为了更好的表现每个节点上到达该节点的路径数目,可以及时的把数目标注上,如上图所示.这样看起来好极了,我开始迫不及待的按照这种方法在棋盘的每个格子的节点上开始标记. 我做的很快.我还不知道是否是正确的,但我很兴奋,没有什么能够阻止我继续写下这些数,不停计算100以内加法对我是一件很过瘾的事情.真不可思议,一分钟内我列举出了所有的数目,我认为肯定是正确的,我必须要证明.归纳法无疑是一个很不错的证明. 已知第一个格子里面,除右上角的节点,其他三个节点的数目已知全部为1,可知从第一个格子的左下角到右上角有两条不同路径.记值为2。有谁还怀疑1+1=2呢? 对于非十字型节点,也可以当做十字形节点处理,把节点左边和下边的十字分支数目定为0 参照下图,假如我已经知道某个节点左边节点和下面节点值的话,只要把这两个值做加法就是该节点值 再次回到这些棋盘上面的数字,总是相邻两个方向的数字做加法得到下一个节点值.把棋盘旋转45°.真难以置信,这不就是杨辉三角吗?这使我想到当把一个没有头脑的虫子放在棋盘左下角让其按照谜题规律移动,那么这些数字足以代表虫子到达某节点的可能性.在加德纳的《啊哈,灵机一动》书上,谜题本身是苏珊为了避免上学碰到讨厌的斯蒂克而需要每天走不同的路径.呵呵,如果加德纳进一步把这个故事扩展的话.我想苏珊可以完全有根据的选择那些斯蒂克选择可能性小的路径.当然我们得残忍的先认同斯蒂克像虫子一样.杨辉三角最重要的性质是第n行的所有数列式n次二项式展开式的系数列.这也很好的说明了到达节点的概率性. 现在我可以欢呼了.甚至像下图这种不规则格子地图也能用这种方法得到正确答案. 也许已经取得了很大的胜利了,不过我已经厌倦了在每个节点做加法.当有一个复杂的棋盘地图或者蜂窝地图时我就不能逼迫自己做着机械的加法.我需要计算机来帮助我得到一个简洁的答案. 我之所以在上面对这个谜题进行分析,是因为我在看书联想到上周上课时练习的几道动态规划问题.寻找路径问题,可以归结为一个简单的递推.而动态规划能够保正每个节点仅被计算一次,减少重复计算.实际上,我在上面的操作中,就是一个手工的动态规划演绎过程. 下面使用动态规划的方法来重新分析棋盘路径问题,并尝试给出算法. 不妨做如下定义:给棋盘上的每个节点定义坐标,最左下方的为f(0,0),最有上方的为f(M,N). 该问题子问题就可以描述为:从(0,0)走到(x,y),每次只能往右或者往上走一步(对应坐标值增1),一共有多少种走法,该点走法的数目记为f(x,y),原问题就是求解f(M,N) 要得到f(x,y)有两个方法,一个是从(x-1，y)往右走一步到(x,y),另一个就是从(x,y-1)走到(x,y).第一个方法有f(x-1,y)种走法,第二种有f(x,y-1)种走法.所以可以得到f(x,y)=f(x-1,y)+f(x,y-1),这个可以通过归纳法证明.由此得到递推公式为: 当x=0或y=0时,f(x,y) = 1; 当x&#62;0且y&#62;0时,f(x,y)=f(x-1,y)+f(x,y-1) /// 求解到坐标(m,n)的不同路径数目 public int HowManyWays(int m,int n) { //创建一个二维表来保存每个节点的路径数目值 int[,] answerMap = new int[m, n]; //初始化表中所有值为1 for (int i = 0; i &#60; m; i++) for (int j = 0; j &#60; n; j++) <p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/c-sharp-coding/how-many-ways.html">到底有多少条路?</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></description>
			<content:encoded><![CDATA[<p><span style="text-decoration: line-through;"><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog1.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-1" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog1_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-1" width="263" height="281" /></a> </span></p>
<p><span style="text-decoration: line-through;">今天</span>(已经是昨天了)又翻了翻《<a href="http://book.douban.com/subject/2249354/">啊哈,灵机一动</a>》(<a href="http://zh.wikipedia.org/zh-cn/%E9%A9%AC%E4%B8%81%C2%B7%E5%8A%A0%E5%BE%B7%E7%BA%B3">马丁·加德纳</a>著),有个排列组合的谜题是<strong>复杂的路</strong>.要求就是寻找在一个错综复杂的路径图里面从一个节点到另一个节点的所有可行路径数目.已规定每次我只能选择向右或者向上移动一个位置.</p>
<p>比如上图是一个棋盘形式的路径图,比较容易找规律,如果我愿意花一个钟头的时间的话,我可以把所有路径列举出来,如果顺利的话,我想可以给我更少的时间.我小时候总是为自己能很快而准确的列举找到答案而洋洋得意.我还记得小时候寻找一个笼子里面兔子和鸡的合适数目,我忙碌的在草稿纸上列举所有兔子的腿数和鸡的腿数.</p>
<p>虽然我知道很少有人愿意按照上面的方法去得到答案,但是如果去做了,我肯定能从中找到规律.不过下面从一个格子开始分析,这样也许是一个很不错的尝试.当我被迫要打开柜子所有抽屉找到所有装了纽扣的抽屉时,从第一个抽屉开始,是个明智的决定,这样不至于后来一团糟,想象一下,当你最后都不知道打开哪些抽屉而又不得不再次打开验证时是多么的令人沮丧.</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog2.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-2" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog2_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-2" width="263" height="281" /></a></p>
<p>显而易见,在一个格子里面,从左下角到右上角有两种路径.如上图A→C→B和A→D→B.</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog3.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-3" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog3_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-3" width="263" height="281" /></a></p>
<p>为了更好的表现每个节点上到达该节点的路径数目,可以及时的把数目标注上,如上图所示.这样看起来好极了,我开始迫不及待的按照这种方法在棋盘的每个格子的节点上开始标记.</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog4.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-4" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog4_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-4" width="263" height="281" /></a></p>
<p>我做的很快.我还不知道是否是正确的,但我很兴奋,没有什么能够阻止我继续写下这些数,不停计算100以内加法对我是一件很过瘾的事情.真不可思议,一分钟内我列举出了所有的数目,我认为肯定是正确的,我必须要证明.归纳法无疑是一个很不错的证明.</p>
<ol>
<li>已知第一个格子里面,除右上角的节点,其他三个节点的数目已知全部为1,可知从第一个格子的左下角到右上角有两条不同路径.记值为2。有谁还怀疑1+1=2呢?</li>
<li>对于非十字型节点,也可以当做十字形节点处理,把节点左边和下边的十字分支数目定为0<br />
<a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog7.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-7" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog7_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-7" width="263" height="281" /></a></li>
<li>参照下图,假如我已经知道某个节点左边节点和下面节点值的话,只要把这两个值做加法就是该节点值<br />
<a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog8.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-8" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog8_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-8" width="263" height="281" /></a></li>
</ol>
<p>再次回到这些棋盘上面的数字,总是相邻两个方向的数字做加法得到下一个节点值.把棋盘旋转45°.真难以置信,这不就是杨辉三角吗?这使我想到当把一个没有头脑的虫子放在棋盘左下角让其按照谜题规律移动,那么这些数字足以代表虫子到达某节点的可能性.在加德纳的《<a href="http://book.douban.com/subject/2249354/">啊哈,灵机一动</a>》书上,谜题本身是苏珊为了避免上学碰到讨厌的斯蒂克而需要每天走不同的路径.呵呵,如果加德纳进一步把这个故事扩展的话.我想苏珊可以完全有根据的选择那些斯蒂克选择可能性小的路径.当然我们得残忍的先认同斯蒂克像虫子一样.杨辉三角最重要的性质是第n行的所有数列式n次二项式展开式的系数列.这也很好的说明了到达节点的概率性.</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog6.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-6" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog6_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-6" width="263" height="281" /></a></p>
<p>现在我可以欢呼了.甚至像下图这种不规则格子地图也能用这种方法得到正确答案.</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog5.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-5" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog5_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-5" width="263" height="281" /></a></p>
<p>也许已经取得了很大的胜利了,不过我已经厌倦了在每个节点做加法.当有一个复杂的棋盘地图或者蜂窝地图时我就不能逼迫自己做着机械的加法.我需要计算机来帮助我得到一个简洁的答案.</p>
<p>我之所以在上面对这个谜题进行分析,是因为我在看书联想到上周上课时练习的几道动态规划问题.寻找路径问题,可以归结为一个简单的递推.而动态规划能够保正每个节点仅被计算一次,减少重复计算.实际上,我在上面的操作中,就是一个手工的动态规划演绎过程.</p>
<p>下面使用动态规划的方法来重新分析棋盘路径问题,并尝试给出算法.</p>
<p>不妨做如下定义:给棋盘上的每个节点定义坐标,最左下方的为<strong><em>f(0,0)</em></strong>,最有上方的为<em><strong>f(M,N)</strong></em>.</p>
<p>该问题子问题就可以描述为:从<em>(0,0)</em>走到<em>(x,y)</em>,每次只能往右或者往上走一步(对应坐标值增1),一共有多少种走法,该点走法的数目记为<em>f(x,y)</em>,原问题就是求解<em>f(M,N)</em></p>
<p>要得到f(x,y)有两个方法,一个是从<em>(x-1，y)</em>往右走一步到<em>(x,y)</em>,另一个就是从<em>(x,y-1)</em>走到<em>(x,y)</em>.第一个方法有<em>f(x-1,y)</em>种走法,第二种有<em>f(x,y-1)</em>种走法.所以可以得到<em><strong>f(x,y)=f(x-1,y)+f(x,y-1)</strong></em>,这个可以通过归纳法证明.由此得到递推公式为:</p>
<ol>
<li>当<em>x=0</em>或<em>y=0</em>时,<em>f(x,y) = 1</em>;</li>
<li>当<em>x&gt;0</em>且<em>y&gt;0</em>时<em>,f(x,y)=f(x-1,y)+f(x,y-1)</em></li>
</ol>
<pre class="brush: csharp; ruler: true">/// 求解到坐标(m,n)的不同路径数目
public int HowManyWays(int m,int n)
{
    //创建一个二维表来保存每个节点的路径数目值
    int[,] answerMap = new int[m, n];
    //初始化表中所有值为1
    for (int i = 0; i &lt; m; i++)
        for (int j = 0; j &lt; n; j++)
            answerMap[i, j] = 1;

    //使用递推来得到每个节点的解
    for (int i = 1; i &lt; m; i++)
        for (int j = 1; j &lt; n; j++)
            answerMap[i, j] = answerMap[i - 1, j] + answerMap[i, j - 1];

    //返回结果
    return answerMap[m - 1, n - 1];
}</pre>
<p>这个算法也就是计算了杨辉三角.如果要计算非规则的棋盘地图节点路径的话,就不能使用简单的二维表,可以考虑使用树形结构或者图来存储地图节点关系数据.不同的移动规则也影响算法过程.</p>
<p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/c-sharp-coding/how-many-ways.html">到底有多少条路?</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></content:encoded>
			<wfw:commentRss>http://catouse.com/c-sharp-coding/how-many-ways.html/feed</wfw:commentRss>
		<slash:comments>519</slash:comments>
		</item>
		<item>
		<title>使用C#Lambda进行泛型参数的数值运算</title>
		<link>http://catouse.com/c-sharp-coding/genericparametersoperation.html</link>
		<comments>http://catouse.com/c-sharp-coding/genericparametersoperation.html#comments</comments>
		<pubDate>Sat, 20 Mar 2010 18:29:21 +0000</pubDate>
		<dc:creator>Catouse</dc:creator>
				<category><![CDATA[C-Sharp]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Lambda]]></category>
		<category><![CDATA[泛型]]></category>
		<category><![CDATA[表达式树]]></category>

		<guid isPermaLink="false">http://catouse.com/?p=21</guid>
		<description><![CDATA[做天写了一个矩阵运算类,我尝试了用泛型来实现,很明显泛型能在我给我的矩阵应用带来更多的选择.矩阵运算在游戏及其AI运用很广泛.不过后来我一想,还是没有必要运用泛型实现.不过昨天的经历让我有兴趣和大家讨论一下C#泛型参数的值运算问题:泛型参数带来的好处的同时也不能忽视其局限性. 泛型参数应用的一个很老的例子就是交换两个数的值了,比如下面的方法实现了两个任意值类型参数的值交换: public void Swap(ref T a, ref T b) { T temp = a; a = b; b = temp; } 当然此方法不能应用于引用类型参数,为了防止泛型编程过程中,不恰当的调入应用参数增加隐性bug,C#对泛型增加了参数约束.在C#中参数约束是通过where关键字实现的,关于更多的泛型参数约束请参考MSDN 上面的方法中参数a,b肯定只能是值类型,所以修正程序第一行如下: public void Swap(ref T a, ref T b) where T:struct 现在我们讨论的不是泛型的概念,不妨考虑一下以下问题: 能否通过泛型实现一个方法来返回所有参数中最大的那个呢? 能否通过泛型实现一个方法来得到一个泛型参数的倒数呢? 能否计算方法中泛型参数的绝对值,或者取负呢? &#8230; 就拿第一个问题吧,很可能我们会写出下面的代码: public T GetTheGreater(T a, T b) where T:struct { if(a&#62;b) return a; else return b; <p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/c-sharp-coding/genericparametersoperation.html">使用C#Lambda进行泛型参数的数值运算</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></description>
			<content:encoded><![CDATA[<p>做天写了一个矩阵运算类,我尝试了用泛型来实现,很明显泛型能在我给我的矩阵应用带来更多的选择.矩阵运算在游戏及其AI运用很广泛.不过后来我一想,还是没有必要运用泛型实现.不过昨天的经历让我有兴趣和大家讨论一下C#泛型参数的值运算问题:<strong>泛型参数带来的好处的同时也不能忽视其局限性</strong>.</p>
<p>泛型参数应用的一个很老的例子就是交换两个数的值了,比如下面的方法实现了两个任意值类型参数的值交换:</p>
<pre class="brush: csharp; ruler: true">public void Swap(ref T a, ref T b)
{
    T temp = a;
    a = b;
    b = temp;
}</pre>
<p>当然此方法不能应用于引用类型参数,为了防止泛型编程过程中,不恰当的调入应用参数增加隐性bug,C#对泛型增加了参数约束.在C#中参数约束是通过<strong>where</strong>关键字实现的,关于更多的泛型参数约束请参考<a href="http://msdn.microsoft.com/zh-cn/library/d5x73970.aspx">MSDN</a><br />
上面的方法中参数a,b肯定只能是值类型,所以修正程序第一行如下:</p>
<pre class="brush: csharp; ruler: true;highlight: [1]">public void Swap(ref T a, ref T b) where T:struct</pre>
<p>现在我们讨论的不是泛型的概念,不妨考虑一下以下问题:</p>
<ol>
<li>能否通过泛型实现一个方法来返回所有参数中最大的那个呢?</li>
<li>能否通过泛型实现一个方法来得到一个泛型参数的倒数呢?</li>
<li>能否计算方法中泛型参数的绝对值,或者取负呢?</li>
<li>&#8230;</li>
</ol>
<p>就拿第一个问题吧,很可能我们会写出下面的代码:</p>
<pre class="brush: csharp; ruler: true">public T GetTheGreater(T a, T b) where T:struct
{
    if(a&gt;b)
        return a;
    else
        return b;
}</pre>
<p>世界上的事情总是有倒霉的一半,程序的第三行不会通过编译检查,已经很明了了,泛型参数是不能进行逻辑判断运算,至少不能进行大于的比较运算.实际上包括所有的逻辑运算和算术运算.由此可见上面的问题在C#里面几乎是不可解决了.<br />
不过我们不要忘了倒霉的一半不是全部,C#3.0引入了表达式树,使得不同类型的值进行运算成为可能.表达式基类Expression提供了丰富的表达式运算方法来帮我们达到目的.我有点迫不及待的给出几行代码,下面是运用表达式树比较两个泛型参数的大小:</p>
<pre class="brush: csharp; ruler: true">///
/// 判断a是否小于b
/// 注意参数顺序,判断的是前一个参数是否小于后一个参数
///
public static bool LessThan(T num1, T num2) where T:struct
{
    //参数表达式树节点1
    ParameterExpression para1 = Expression.Parameter(typeof(T), "left");
    //参数表达式树节点2
    ParameterExpression para2 = Expression.Parameter(typeof(T), "right");
    //两个参数节点构成关系为比较大小的二叉树节点
    BinaryExpression expsLessThan = Expression.LessThan(para1, para2);
    //定义lambda表达式
    Expression&gt; exps = Expression.Lambda
        &gt;(expsLessThan, new ParameterExpression[] { para1, para2 });
    //转化为匿名函数指针
    Func myFunction = exps.Compile();
    //返回执行结果
    return myFunction(num1, num2);
}</pre>
<p>关于表达式树的更多概念请参见<a href="http://msdn.microsoft.com/zh-cn/library/system.linq.expressions(VS.95).aspx">System.Linq.Expressions 命名空间</a>这里不再重复MSDN的内容<br />
当然上面的是逻辑判断的例子,如果是算术运算呢?我们只要改变对Expression代理的封装就是.</p>
<pre class="brush: csharp; ruler: true">///
/// 将两个泛型参数做加法运算
///
public static T Add(T num1, T num2) where T:struct
{
    //参数表达式树节点1
    ParameterExpression para1 = Expression.Parameter(typeof(T), "left");
    //参数表达式树节点2
    ParameterExpression para2 = Expression.Parameter(typeof(T), "right");
    //两个参数节点构成关系为求和的二叉树节点
    BinaryExpression expsAdd = Expression.LessThan(para1, para2);
    //定义lambda表达式
    Expression&gt; exps = Expression.Lambda
        &gt;(expsLessThan, new ParameterExpression[] { para1, para2 });
    //转化为匿名函数指针
    Func myFunction = exps.Compile();
    //返回执行结果
    return myFunction(num1, num2);
}</pre>
<p>上面的都是二元运算,如果是一元运算呢?有点点不同就是注意对lambda表达式的中的代理参数封装,还有就是二叉树节点为UnaryExpression(包含一元运算的表达式),而不是BinaryExpression(包含二元运算的表达式)<br />
下面是一个求负的方法</p>
<pre class="brush: csharp; ruler: true">///
/// 求给定泛型参数的负数
///
public static T Negate(T num) where T:struct
{
    //创建一个参数表达式树节点
    ParameterExpression para1 = Expression.Parameter(typeof(T), "left");
    //构成一个求负的一元表达式
    UnaryExpression expsNegate = Expression.Negate(p1);
    //定义lambda表达式
    Expression&gt; exps = Expression.Lambda
        &gt;(expsLessThan, new ParameterExpression[] { para1});
    //转化为匿名函数指针
    Func myFunction = exps.Compile();
    //返回执行结果
    return myFunction(num);
}</pre>
<p>有了上面三个例子,基本上所有的逻辑运算和算术运算都不是问题了,不过我们如果在定义的泛型类中一个个定义这些方法肯定很别扭,不仅破坏泛型类本身的聚合性,而且重复写也麻烦,所以我们可以将这些运算方法封装为另外一个泛型类,比如取个名字就叫 CalculateGeneric,实际上我就是这么叫的.</p>
<pre class="brush: csharp; ruler: true">///
/// 泛型数值类型计算类
///
public static class CalculateGeneric where T:struct
{
    /// 返回此数值泛型的0值
    public static T Zero;

    /// 实现两个泛型变量的相加算术运算
    public static T Add(T num1, T num2);

    /// 判断两个泛型变量值是否相等
    public static bool Equal(T num1, T num2);

    /// 取倒数
    public static T Reciprocal(T num);

    ///更多丰富的计算类型....
}</pre>
<p>你可能会注意到上面的类中有一个访问器是返回0值,另外你还可能注意到取倒数的方法.所以我还要补充一个问题就是怎样解决泛型参数常量1和0的表示,比如我要通过泛型方法得到不同类型数值的倒数,我就要得到数值1.Expression类也没有提供取倒数的表达式运算方法.<br />
我还没有很好的办法来解决这个问题,不过我临时是这样来解决的:</p>
<ul>
<li>通过<a href="http://msdn.microsoft.com/zh-cn/library/xwth0h0d.aspx">泛型代码中的默认关键字default </a>来变相获取0值,这有泛型参数如果为值类型,则默认值为0</li>
<li>将一个不为0值的泛型参数和自身做除法运算则得到数值1</li>
</ul>
<p>我不能保证上面的解决方法适合所有情况,欢迎大家提出错误或者分享你的解决方案.<br />
另外说明,不能乱用这种方法来对泛型操作,毕竟这样修改了泛型的本意.<span style="color: #808080;">(2010-4-4 15:57:01更新)</span></p>
<p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/c-sharp-coding/genericparametersoperation.html">使用C#Lambda进行泛型参数的数值运算</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></content:encoded>
			<wfw:commentRss>http://catouse.com/c-sharp-coding/genericparametersoperation.html/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
	</channel>
</rss>

