﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-textbox-随笔分类-c#</title><link>http://www.cnitblog.com/textbox/category/8652.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 26 Sep 2011 14:38:50 GMT</lastBuildDate><pubDate>Mon, 26 Sep 2011 14:38:50 GMT</pubDate><ttl>60</ttl><item><title>原来asp.net mvc 的开发就象在开发一堆的宏.</title><link>http://www.cnitblog.com/textbox/archive/2011/01/10/72612.html</link><dc:creator>零度</dc:creator><author>零度</author><pubDate>Mon, 10 Jan 2011 03:20:00 GMT</pubDate><guid>http://www.cnitblog.com/textbox/archive/2011/01/10/72612.html</guid><wfw:comment>http://www.cnitblog.com/textbox/comments/72612.html</wfw:comment><comments>http://www.cnitblog.com/textbox/archive/2011/01/10/72612.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/textbox/comments/commentRss/72612.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/textbox/services/trackbacks/72612.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要:    接触了几天mvc,感觉mvc就象是写一大堆的(系统自带,自己扩展控件)宏,然后把这些宏镶嵌到mvc 的aspx页面里.客户端的html就是宏展开的结果代码.这些宏多数都是镶嵌在一个div里面(目的就是达到div+css)吧.说到前端设计和后端设计分离(分离了吗?).<br>&nbsp;&nbsp;<a href='http://www.cnitblog.com/textbox/archive/2011/01/10/72612.html'>阅读全文</a><img src ="http://www.cnitblog.com/textbox/aggbug/72612.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/textbox/" target="_blank">零度</a> 2011-01-10 11:20 <a href="http://www.cnitblog.com/textbox/archive/2011/01/10/72612.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C# 性能优化方面的总结(转)</title><link>http://www.cnitblog.com/textbox/archive/2010/07/07/67238.html</link><dc:creator>零度</dc:creator><author>零度</author><pubDate>Wed, 07 Jul 2010 09:09:00 GMT</pubDate><guid>http://www.cnitblog.com/textbox/archive/2010/07/07/67238.html</guid><wfw:comment>http://www.cnitblog.com/textbox/comments/67238.html</wfw:comment><comments>http://www.cnitblog.com/textbox/archive/2010/07/07/67238.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/textbox/comments/commentRss/67238.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/textbox/services/trackbacks/67238.html</trackback:ping><description><![CDATA[
		<br />
		<b>源地址 http://blog.csdn.net/liuyang_16888/archive/2008/03/13/2177069.aspx<br /></b>
		<br />
		<b>1 </b>
		<b>
						垃圾回
收
				</b>
		<br />
				垃圾回收解放了手工管理对象的工作，提高了程序的健壮性，但副作用就是程
序代码可能对于对象创建变得随意。
		
		<br />
				1.1  
		<br />
				由于垃圾回收的代价较高，所以C#程序开发要遵循的一个基
本原则就是避免不必要的对象创建。以下列举一些常见的情形。
		<br />
				
						1.1.1
				
				
				
				避免循环创建对象 ★
		
		<br />
				如果对象并不会随每次循环而改变状态，那么在循环中反复创建对象将带来性
能损耗。高效的做法是将对象提到循环外面创建。
		
		<br />
				
						1.1.2
				
				
				
				在需要逻辑分支中创建对象
		
		<br />
				如果对象只在某些逻辑分支中才被用到，那么应只在该逻辑分支中创建对象。
		
		<br />
				
						1.1.3
				
				
				
				使用常量避免创建对象
		
		<br />
				程序中不应出现如 new Decimal(0) 之类的
代码，这会导致小对象频繁创建及回收，正确的做法是使用Decimal.Zero常量。我们有设计
自己的类时，也可以学习这个设计手法，应用到类似的场景中。
		<br />
				1.2 
		
		<br />
				如果类包含析构函数，由创建对象时会在 Finalize 队列中添加对象的引用，以保证当对象无法可达时，仍然可以调用到 Finalize 
方法。垃圾回收器在运行期间，会启动一个低优先级的线程处理该队列。相比之下，没有析构函数的对
象就没有这些消耗。如果析构函数为空，这个消耗就毫无意义，只会导致性能降低！因此，不要使用空
的析构函数。
		<br />
				在实际情况中，许多曾在析构函数中包含处理代码，但后来因
为种种原因被注释掉或者删除掉了，只留下一个空壳，此时应注意把析构函数本身注释掉或删除掉。
		<br />
				1.3 
		
		<br />
				垃圾回收事实上只支持托管内在的回收，对于其他的非托管资源，例如 
Window GDI 句柄或数据库连接，在析构函数中释放这些资源有很大问题。
原因是垃圾回收依赖于内在紧张的情况，虽然数据库连接可能已濒临耗尽，但如果内存还很充足的话，垃圾回收是不会运行的。
		<br />
				C#
		
		<br />
				为防止对象的 Dispose 方法不被调用的情况发生，
一般还要提供析构函数，两者调用一个处理资源释放的公共方法。同时，Dispose 方法应调用System.GC.SuppressFinalize(this)，
告诉垃圾回收器无需再处理 Finalize 方法了。
		<br /><b>2 String </b><b>
						操作
				</b><br />
				2.1 
		
		<br />
				String
				是不变类，使用 + 操作连接字符串将会导致
创建一个新的字符串。如果字符串连接次数不是固定的，例如在一个循环中，则应该使用 StringBuilder类来做字符串连接工作。因为 StringBuilder 内部有一个 StringBuffer ，连接操作不会每次分配新的字符串空间。只有当连接后的字符串超出 
Buffer 大小时，才会申请新的 Buffer 空间。典型代码如下：
		<br />
				StringBuilder
				sb = new StringBuilder(256 );
		<br />
				for ( int
 i = 0 ; i &lt; Results.Count; i ++ )
		<br />{
		<br />
				sb.Append (Results[i]);
		<br />} 
		<br />
				如果连接次数是固定的并且只有几次，此时应该直接用 + 号
连接，保持程序简洁易读。实际上，编译器已经做了优化，会依据加号次数调用不同参数个数的 String.Concat
 方法。例如：String str
 = str1+ str2 + str3 + str4;
		<br />
				会被编译为 String.Concat(str1,
 str2, str3, str4)。该方法内部会计算总的 String 
长度，仅分配一次，并不会如通常想象的那样分配三次。作为一个经验值，当字符串连接操作达到 10 次
以上时，则应该使用StringBuilder。
		<br />
				这里有一个细节应注意：StringBuilder
				
				内部 Buffer 的缺省值为 16 ，这个值实
在太小。按 StringBuilder 的使用场景，Buffer 
肯定得重新分配。经验值一般用 256 作为 Buffer 
的初值。当然，如果能计算出最终生成字符串长度的话，则应该按这个值来设定Buffer 的初值。
使用 new StringBuilder(256)就
将 Buffer 的初始长度设为了256。
		<br />
				2.2 
		
		<br />
				String
		
		<br />
				例如，bool.Parse方
法本身已经是忽略大小写的，调用时不要调用ToLower方法。
		<br />
				另一个非常普遍的场景是字符串比较。高效的做法是使用 Compare 方
法，这个方法可以做大小写忽略的比较，并且不会创建新字符串。
		<br />
				还有一种情况是使用 HashTable的时候，有时候无法保证传递 key 的大小写是否符合预期，往往会把 key 强
制转换到大写或小写方法。实际上 HashTable 
有不同的构造形式，完全支持采用忽略大小写的 key: new HashTable(StringComparer.OrdinalIgnoreCase)。
		<br />
				2.3 
		
		<br />
				将String对象的Length属性与0比较是最快的方法：if (str.Length == 0)其次是与String.Empty常
量或空串比较：if (str == String.Empty)
或if (str == "")
		<br />
				　注：C#在编译时会将程序集中声明的所有字符串常量放到
保留池中（intern pool），相同常量不会重复分配。
		<br /><b>3 </b><br />
				3.1 
		
		<br />
				线程同步是编写多线程程序需要首先考虑问题。C#为同步提
供了 Monitor、Mutex、AutoResetEvent 和ManualResetEvent对象来分别包装 Win32 的临界区、互斥对象和事件对象这几种基础的同步机制。C#还提供了一个lock语句，方便使用，编译器会自动生成适当的 Monitor.Enter
 和 Monitor.Exit 调用。
		<br />
				
						3.1.1
				
				
				
				同步粒度
		
		<br />
				同步粒度可以是整个方法，也可以是方法中某一段代码。为方法指定 MethodImplOptions.Synchronized属性将标记对整个方法同
步。例如：
		<br />[MethodImpl(MethodImplOptions.Synchronized)]
		<br />
				public static SerialManagerGetInstance()
		<br />{
		<br />
				if (instance == null )
		<br />{
		<br />
				instance = new SerialManager();
		<br />} 
		<br />
				return instance;
		<br />} 
		<br />
				通常情况下，应减小同步的范围，使系统获得更好的性能。简单将整个方法标
记为同步不是一个好主意，除非能确定方法中的每个代码都需要受同步保护。
		
		<br />
				
						3.1.2
				
				
				
				同步策略
		
		<br />
				使用 lock 进行同步，同步对象可以选择 Type、this 或为同步目的专门构造的成员变量。
		<br />
				避免锁定Type
		
		<br />
				锁定Type对象会影响同一进程中所有AppDomain该类型的所有实例，这不仅可能导
致严重的性能问题，还可能导致一些无法预期的行为。这是一个很不好的习惯。即便对于一个只包含static方法的类型，也应额外构造一个static的成员变量，让此成员变量作为锁定对象。
		<br />
				避免锁定 this
		
		<br />
				锁定 this 会影响该实例的所有方法。假设对象obj有
 A 和 B 两个方法，其中 A 方法使用
 lock(this) 对方法中的某段代码设置同步保护。现在，因为某种原因，B 方法也开始使用
 lock(this) 来设置同步保护了，并且可能为了完全不同的目的。这样，A 
方法就被干扰了，其行为可能无法预知。所以，作为一种良好的习惯，建议避免使用lock(this) 这
种方式。
		<br />
				使用为同步目的专门构造的成员变量
		
		<br />
				这是推荐的做法。方式就是 new 一个 object 对象， 该对象仅仅用于同步目的。
		<br />
				如果有多个方法都需要同步，并且有不同的目的，那么就可以为些分
别建立几个同步成员变量。
		<br />
				
						3.1.4
				
				
				
				集合同步
		
		<br />
				C#
		
		<br />// Creates andinitializes a new ArrayList
		<br />
				ArrayList
				myAL = new ArrayList();
		<br />
				
						myAL.Add
				
				( " The " );
		<br />
				
						myAL.Add
				
				( " quick " );
		<br />
				
						myAL.Add
				
				( " brown " );
		<br />
				
						myAL.Add
				
				( " fox " );
		<br />// Creates asynchronized wrapper around the ArrayList
		<br />
				ArrayList
				mySyncdAL = ArrayList.Synchronized(myAL); 
		<br />
				调用 Synchronized 方法会返回一个可保证所
有操作都是线程安全的相同集合对象。考虑mySyncdAL[0]
 = mySyncdAL[0]+ "test" 这一语句，读和写一共要用到
两个锁。一般讲，效率不高。推荐使用 SyncRoot 属性，可以做比较精细的控制。
		<br />
				3.2 
		
		<br />
				存取 NameDataSlot的 Thread.GetData 和 
Thread.SetData 方法需要线程同步，涉及两个锁：一个是 
LocalDataStore.SetData 方法需要在 AppDomain 
一级加锁，另一个是 ThreadNative.GetDomainLocalStore 
方法需要在 Process 一级加锁。如果一些底层的基础服务使用了 NameDataSlot，
将导致系统出现严重的伸缩性问题。
		<br />
				规避这个问题的方法是使用 ThreadStatic变量。示例如下：
		<br />
				public sealed class InvokeContext
		<br />{
		<br />
				[ThreadStatic]
		
		<br />
				private
				 static InvokeContext
 current;
		
		<br />
				private
				
						Hashtable
 maps = new Hashtable();
		<br />} 
		<br />
				
						 
				
		
		<br />
				3.3 
		
		<br />
				
						3.3.1
				
				
				
				使用Double Check 技术创建对象
		
		<br />
				internal
				IDictionary KeyTable
		<br />{
		<br />
				get
				
						
						
				
		
		<br />
				{
		
		<br />
				if
				 ( this ._keyTable
 == null )
		
		<br />
				{
		
		<br />
				lock
				 ( base ._lock)
		
		<br />
				{
		
		<br />
				if
				 ( this ._keyTable
 == null )
		
		<br />
				{
		
		<br />
				this
				 ._keyTable
 = new Hashtable();
		<br />
				} 
		
		<br />
				} 
		
		<br />
				} 
		
		<br />
				return
				 this ._keyTable;
		
		<br />
				} 
		
		<br />} 
		<br />
				
						创建单例对象
				
				是很常见的一种编程情况。一般在 lock 语句后就会直接创建对象了，但这不够安
全。因为在 lock 锁定对象之前，可能已经有多个线程进入到了第一个 if 
语句中。如果不加第二个 if 语句，则单例对象会被重复创建，新的实例替代掉旧的实例。如果单例对象中已有数据不允许被破坏或者别的什么原因，则应考虑使用 DoubleCheck 技术。
		<br /><b>4 </b><br />
				4.1 
		
		<br />
				CLR
		
		<br />
				需要注意的是：方法中的局部变量不是从堆而是从栈上分配，所以C#不会做清零工作。如果使用了未赋
值的局部变量，编译期间即会报警。不要因为有这个印象而对所有类的成员变量也做赋值动作，两者的机理完全不同！
		<br />
				4.2 ValueType
				和 ReferenceType
		
		<br />
				
						4.2.1
				
				
				
				以引用方式传递值类型参数
		<br />
				
						值类型
				
				从调用栈分配，引用类型从托管堆分配。当
值类型用作方法参数时，默认会进行参数值复制，这抵消了值类型分配效率上的优势。作为一项基本技巧，以引用方式传递值类型参数可以提高性能。
		<br />
				
						4.2.2
				
				
				
				为 ValueType提供 
Equals 方法
		<br />
				.net 
		
		<br />
				public
				struct
 Rectangle
		<br />{
		<br />
				public double Length;
		
		<br />
				public
				 double Breadth;
		
		<br />
				public
				 override bool
 Equals ( objectob)
		
		<br />
				{
		
		<br />
				if
				 (ob is Rectangle)
		
		<br />
				return
				
						Equels 
((Rectangle)ob))
		
		<br />
				else
				
						
						
				
		
		<br />
				return false ;
		
		<br />
				} 
		
		<br />
				private
				
						bool 
Equals (Rectangle rect)
		<br />
				{
		
		<br />
				return
				 this .Length == rect.Length&amp;&amp;
 this .Breadth == rect.Breach;
		
		<br />
				} 
		
		<br />} 
		<br />
				
						4.2.3
				
				
				
				避免装箱和拆箱
		
		<br />
				C#
		
		<br />
				一种经常的情形出现在使用集合类型时。例如：
		
		<br />
				ArrayList al = new ArrayList();
		<br />
				for ( int
 i = 0 ; i &lt; 1000 ; i ++ )
		<br />{
		<br />
				
						
								al.Add
						
				
				
						(
				
				
						i
				
				);// Implicitly boxed because 
Add() takes an object 
		
		<br />} 
		<br />
				
						int
				
 f = ( int )al[ 0]; // The element is 
unboxed  
		<br /><b>5 </b><br />
				异常也是现代语言的典型特征。与传统检查错误码的方式相比，异常是强制性
的（不依赖于是否忘记了编写检查错误码的代码）、强类型的、并带有丰富的异常信息（例如调用栈）。
		<br />
				5.1 
		
		<br />
				关于异常处理的最重要原则就是：不要吃掉异常。这个问题与性能无关，但对
于编写健壮和易于排错的程序非常重要。这个原则换一种说法，就是不要捕获那些你不能处理的异常。
		
		<br />
				吃掉异常是极不好的习惯，因为你消除了解决问题的线索。一旦出现错误，定
位问题将非常困难。除了这种完全吃掉异常的方式外，只将异常信息写入日志文件但并不做更多处理的做法也同样不妥。
		
		<br />
				5.2 
		
		<br />
				有些代码虽然抛出了异常，但却把异常信息吃掉了。
		
		<br />
				为异常披露详尽的信息是程序员的职责所在。如果不能在保留原始异常信息含
义的前提下附加更丰富和更人性化的内容，那么让原始的异常信息直接展示也要强得多。千万不要吃掉异常。
		
		<br />
				5.3 
		
		<br />
				抛出异常和捕获异常属于消耗比较大的操作，在可能的情况下，应通过完善程
序逻辑避免抛出不必要不必要的异常。与此相关的一个倾向是利用异常来控制处理逻辑。尽管对于极少数的情况，这可能获得更为优雅的解决方案，
但通常而言应该避免。
		<br />
				5.4 
		
		<br />
				如果是为了包装异常的目的（即加入更多信息后包装成新异常），那么是合理
的。但是有不少代码，捕获异常没有做任何处理就再次抛出，这将无谓地增加一次捕获异常和抛出异常的消耗，对性能有伤害。
		
		<br /><b>6 </b><br />
				反射是一项很基础的技术，它将编译期间的静态绑定转换为延
迟到运行期间的动态绑定。在很多场景下（特别是类框架的设计），可以获得灵活易于扩展的架构。但带来的问题是与静态绑定相比，动态绑定会对性能造成较大的
伤害。
		<br />
				6.1 
		
		<br />
				typecomparison 
				：类型判断，主要包括 is 和 typeof两个操作符及对象实例上的 GetType
 调用。这是最轻型的消耗，可以无需考虑优化问题。注意 typeof 运算符比对象实例上的 GetType 
方法要快，只要可能则优先使用 typeof 运算符。
		<br />
				memberenumeration 
				： 成员枚举，用于访问反射相关的元数据信息，例如Assembly.GetModule、Module.GetType、Type对象上的IsInterface、IsPublic、GetMethod、GetMethods、GetProperty、GetProperties、GetConstructor调用等。尽管元数据都会被CLR缓存，但部分方法的调用消耗仍非常大，不过这类方法调用频度不会很高，所以总体看性能损失程度中等。
		<br />
				memberinvocation
				：成员调用，包括动态创建对象及动态调用对象方法，主要有Activator.CreateInstance、Type.InvokeMember等。
		<br />
				6.2 
		
		<br />
				C#
		
		<br />
				　　1. Type.InvokeMember
		
		<br />
				　　2. ContructorInfo.Invoke
		
		<br />
				　　3. Activator.CreateInstance(Type)
		<br />
				　　4. Activator.CreateInstance(
				assemblyName, typeName)
		<br />
				　　5. Assembly.CreateInstance(
				typeName)
		<br />
				最快的是方式 3 ，与 Direct Create 的差异在一个数量级之内，约慢 7 倍的
水平。其他方式，至少在 40倍以上，最
慢的是方式 4 ，要慢三个数量级。
		<br />
				6.3 
		
		<br />
				方法调用分为编译期的早期绑定和运行期的动态绑定两种，称为Early-
Bound Invocation和Late-Bound Invocation。Early-Bound
 Invocation可细分为Direct-call、Interface-call和Delegate-call。Late-Bound Invocation主要有Type.InvokeMember和MethodBase.Invoke，还可以通过使用LCG（Lightweight
 Code Generation）技术生成IL代码来实现动态调用。
		<br />
				从测试结果看，相比Direct Call，Type.InvokeMember要接近慢三个数
量级；MethodBase.Invoke虽然比Type.InvokeMember要
快三倍，但比Direct Call仍慢270倍左右。可见动态方法调用的性能是非常低下的。我们
的建议是：除非要满足特定的需求，否则不要使用！
		<br />
				6.4 
		
		<br />
				模式
		
		<br />
				　　1． 如果可能，则避免使用反射和动态绑定
		<br />
				　　2． 使用接口调用方式将动态绑定改造为早期绑定
		<br />
				　　3． 使用Activator.CreateInstance(Type)方式动态创建对象
		<br />
				　　4． 使用typeof操作符代替GetType调
用
		<br />
				反模式
		
		<br />
				　　1． 在已获得Type的
情况下，却使用Assembly.CreateInstance(type.FullName)
		<br /><b>7 </b><br />
				这里描述一些应用场景下，可以提高性能的基本代码技巧。对处于关键路径的
代码，进行这类的优化还是很有意义的。普通代码可以不做要求，但养成一种好的习惯也是有意义的。
		
		<br />
				7.1 
		
		<br />
				可以把循环的判断条件用局部变量记录下来。局部变量往往被编译器优化为直
接使用寄存器，相对于普通从堆或栈中分配的变量速度快。如果访问的是复杂计算属性的话，提升效果将更明显。for (int
 i = 0, j = collection.GetIndexOf(item);i &lt; j; i++)
		<br />
				需要说明的是：这种写法对于CLR集合类的Count属性没有意义，原因是编译器已经按这种方式做了特别的优化。
		<br />
				7.2 
		
		<br />
				拼装好之后再删除是很低效的写法。有些方法其循环长度在大部分情况下为1，
这种写法的低效就更为明显了：
		<br />
				public static string ToString(MetadataKey entityKey)
		<br />{
		<br />
				string
				
						str = ""
 ;
		
		<br />
				object
				 [] vals =
 entityKey.values;
		
		<br />
				for
				 ( inti= 0 ; i &lt; vals.Length; i ++ )
		<br />
				{
		
		<br />
				
						str
				
 += " , " + vals[i].ToString();
		<br />
				} 
		
		<br />
				return
				
						str == 
"" ?"" : str.Remove( 0 , 1 );
		
		<br />} 
		<br />
				推荐下面的写法：
		
		<br />
				if (str.Length
 == 0 )
		<br />
				
						str
				
 = vals[i].ToString();
		<br />
				else
				
				
		
		<br />
				
						str
				
 += " , " + vals[i].ToString();
		<br />
				其实这种写法非常自然，而且效率很高，完全不需要用个Remove方
法绕来绕去。
		<br />
				7.3 
		
		<br />
				获取集合元素时，有时需要检查元素是否存在。通常的做法是先调用ContainsKey（或Contains）
方法，然后再获取集合元素。这种写法非常符合逻辑。 
		<br />
				但如果考虑效率，可以先直接获取对象，然后判断对象是否为null来
确定元素是否存在。对于Hashtable，
这可以节省一次GetHashCode调用和n次
Equals比较。
		<br />
				如下面的示例：
		
		<br />
				public
				IData
 GetItemByID(Guid id)
		<br />{
		<br />
				IData data1 = null ;
		<br />
				if ( this .idTable.ContainsKey(id.ToString())
		<br />{
		<br />data1 = this
 .idTable[id.ToString()]as IData;
		<br />} 
		<br />
				return data1;
		<br />} 
		<br />
				其实完全可用一行代码完成：return
				 this.idTable[id] as IData;
		<br />
				7.4 
		
		<br />
				考虑如下示例，其中包含了两处类型转换： 
		
		<br />
				if (obj
 is SomeType)
		<br />{
		<br />
				SomeType
				
						st = (SomeType)obj;
		<br />
				
						st.SomeTypeMethod
				
				();
		<br />} 
		<br />
				效率更高的做法如下：
		
		<br />
				SomeType
				st = obj as SomeType;
		<br />
				if (st
 != null )
		<br />{
		<br />
				
						
								st.SomeTypeMethod
						
				
				
						(
				
				);
		
		<br />} 
		<br /><b>8 Hashtable</b><br />
				
						Hashtable
				
				是一种使用非常频繁的基础集合类型。需要理解影响Hashtable的
效率有两个因素：一是散列码（GetHashCode方法），二是等值比较（Equals方法）。Hashtable首先使用键的散列码将对象分布
到不同的存储桶中，随后在该特定的存储桶中使用键的Equals方法进行查找。
		<br />
				良好的散列码是第一位的因素，最理想的情况是每个不同的键都有不同的散列
码。Equals方法也很重要，因为散列只需要做一次，而存储桶中查找键可能需要做多次。从实际经验看，使用Hashtable时，Equals方法的消耗一般会占
到一半以上。
		<br />
				
						System.Object
				
				类提供了默认的GetHashCode实
现，使用对象在内存中的地址作为散列码。我们遇到过一个用Hashtable来缓存
对象的例子，每次根据传递的OQL表达式构造出一个ExpressionList对
象，再调用QueryCompiler的方法编译得到CompiledQuery对
象。以ExpressionList对象和CompiledQuery对
象作为键值对存储到Hashtable中。ExpressionList对
象没有重载GetHashCode实现，其超类ArrayList也没有，这样最后用的就是System.Object类
的GetHashCode实现。由于ExpressionList对象会每次构造，因此它的HashCode每
次都不同，所以这个CompiledQueryCache根本就没有起到预想的作用。这个小小的疏
漏带来了重大的性能问题，由于解析OQL表达式频繁发生，导致CompiledQueryCache不
断增长，造成服务器内存泄漏！解决这个问题的最简单方法就是提供一个常量实现，例如让散列码为常量0。虽然这会导致所有对象汇聚到同一个存储桶中，效率不
高，但至少可以解决掉内存泄漏问题。当然，最终还是会实现一个高效的GetHashCode方法
的。
		以上介绍这些Hashtable机
理，主要是希望大家理解：如果使用Hashtable，你应该检查一下对象是否提供了适当的GetHashCode和Equals方法实现。否
则，有可能出现效率不高或者与预期行为不符的情况。<img src ="http://www.cnitblog.com/textbox/aggbug/67238.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/textbox/" target="_blank">零度</a> 2010-07-07 17:09 <a href="http://www.cnitblog.com/textbox/archive/2010/07/07/67238.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网页分析</title><link>http://www.cnitblog.com/textbox/archive/2010/06/21/66893.html</link><dc:creator>零度</dc:creator><author>零度</author><pubDate>Mon, 21 Jun 2010 03:26:00 GMT</pubDate><guid>http://www.cnitblog.com/textbox/archive/2010/06/21/66893.html</guid><wfw:comment>http://www.cnitblog.com/textbox/comments/66893.html</wfw:comment><comments>http://www.cnitblog.com/textbox/archive/2010/06/21/66893.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/textbox/comments/commentRss/66893.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/textbox/services/trackbacks/66893.html</trackback:ping><description><![CDATA[  很久没给这里写东西了.工作,家庭等等.每一样东西都在消耗着我的时间,近来在忙帮朋友写一个分析搜索引擎搜索出来的结果并过滤网页内容的系统.现在基本的功能都实现了.下面我就大概的总结一下此类的软件的程序技术点.<br /><br />1.获取一个URL的Web源码. (这里涉及到网页的编码转换问题,我的程序是以UTF-8为主的,所有网页下载下来都会转换成UTF-8编码 )<br />2.利用正则表达式匹配引擎的搜索源码.匹配出想要的信息. 再度正则表达式分析匹配出来的信息,<br />3.多线程操作<br />4.自动发邮件.自动注册邮箱.<br />5.分析http header  <br />6.自动翻译关键字.<br />7.maxcode加密. 试用版.<br /><br />该软件支持分析全球27个引擎,支持各国语言的搜索分析. <br /><br /><img src ="http://www.cnitblog.com/textbox/aggbug/66893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/textbox/" target="_blank">零度</a> 2010-06-21 11:26 <a href="http://www.cnitblog.com/textbox/archive/2010/06/21/66893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>画组织结构图 </title><link>http://www.cnitblog.com/textbox/archive/2010/02/01/64084.html</link><dc:creator>零度</dc:creator><author>零度</author><pubDate>Mon, 01 Feb 2010 01:46:00 GMT</pubDate><guid>http://www.cnitblog.com/textbox/archive/2010/02/01/64084.html</guid><wfw:comment>http://www.cnitblog.com/textbox/comments/64084.html</wfw:comment><comments>http://www.cnitblog.com/textbox/archive/2010/02/01/64084.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/textbox/comments/commentRss/64084.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/textbox/services/trackbacks/64084.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 公司前些時間要畫這個組織圖，剛開始還真無從下手。經過幾天的摸索終於弄出來了。 以下是效果圖，用c# vs2008 寫出來的。下面就講一下原理：該圖是從左向右從下往上畫。主要是確定每個節點的X座標，而每個X座標都有三種可能性得到。如果是画纵向就主要确定每个节点的Y坐标。节点可以是控件也可以自己画图，只要是实现IOrgCharNodeControl接口和 IOrgCharControlBuilder ...&nbsp;&nbsp;<a href='http://www.cnitblog.com/textbox/archive/2010/02/01/64084.html'>阅读全文</a><img src ="http://www.cnitblog.com/textbox/aggbug/64084.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/textbox/" target="_blank">零度</a> 2010-02-01 09:46 <a href="http://www.cnitblog.com/textbox/archive/2010/02/01/64084.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>