﻿<?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>博客园-二把刀</title><link>http://www.cnblogs.com/zohong/</link><description>比大海和天空更广阔是人的胸怀，而且是男人的胸怀！</description><language>zh-cn</language><lastBuildDate>Wed, 19 Nov 2008 07:48:13 GMT</lastBuildDate><pubDate>Wed, 19 Nov 2008 07:48:13 GMT</pubDate><ttl>60</ttl><item><title>sql server 查看执行效率低下的语句</title><link>http://www.cnblogs.com/zohong/archive/2008/11/01/1324335.html</link><dc:creator>二把刀</dc:creator><author>二把刀</author><pubDate>Sat, 01 Nov 2008 09:40:00 GMT</pubDate><guid>http://www.cnblogs.com/zohong/archive/2008/11/01/1324335.html</guid><description><![CDATA[<p><font  color="#0000FF"><span  style="color: #000000; ">就是在测量功能时，先以下命令清除sql server的缓存</span></font></p>
<p><span style="color: #0000FF;"><strong>d</strong></span><strong>bcc&#160;freeProcCache</strong></p>
<p>在点击某个按钮,执行完后,再执行下面语句,就可以知道系统运行什么Sql和多少次了,其主要慢语句是那些了;</p>
<p><font color="#333333" face="verdana" size="3"><span style="border-collapse: collapse; font-size: 13px; line-height: 17px;">
<div class="cnblogs_code"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF;"><strong>SELECT</strong></span><span style="color: #000000;"><strong>&#160;creation_time&#160;&#160;N</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>语句编译时间</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;,last_execution_time&#160;&#160;N</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>上次执行时间</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;,total_physical_reads&#160;N</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>物理读取总次数</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;,total_logical_reads</strong></span><span style="color: #808080;"><strong>/</strong></span><span style="color: #000000;"><strong>execution_count&#160;N</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>每次逻辑读次数</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;,total_logical_reads&#160;&#160;N</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>逻辑读取总次数</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;,total_logical_writes&#160;N</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>逻辑写入总次数</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;,execution_count&#160;&#160;N</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>执行次数</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;,total_worker_time</strong></span><span style="color: #808080;"><strong>/</strong></span><span style="color: #800000; "><strong>1000</strong></span><span style="color: #000000;"><strong>&#160;N</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>所用的CPU总时间ms</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;,total_elapsed_time</strong></span><span style="color: #808080;"><strong>/</strong></span><span style="color: #800000; "><strong>1000</strong></span><span style="color: #000000;"><strong>&#160;&#160;N</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>总花费时间ms</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;,(total_elapsed_time&#160;</strong></span><span style="color: #808080;"><strong>/</strong></span><span style="color: #000000;"><strong>&#160;execution_count)</strong></span><span style="color: #808080;"><strong>/</strong></span><span style="color: #800000; "><strong>1000</strong></span><span style="color: #000000;"><strong>&#160;&#160;N</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>平均时间ms</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;,</strong></span><span style="color: #FF00FF;"><strong>SUBSTRING</strong></span><span style="color: #000000;"><strong>(st.</strong></span><span style="color: #0000FF;"><strong>text</strong></span><span style="color: #000000;"><strong>,&#160;(qs.statement_start_offset</strong></span><span style="color: #808080;"><strong>/</strong></span><span style="color: #800000; "><strong>2</strong></span><span style="color: #000000;"><strong>)&#160;</strong></span><span style="color: #808080;"><strong>+</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #800000; "><strong>1</strong></span><span style="color: #000000;"><strong>,<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;((</strong></span><span style="color: #FF00FF;"><strong>CASE</strong></span><span style="color: #000000;"><strong>&#160;statement_end_offset&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</strong></span><span style="color: #0000FF;"><strong>WHEN</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #808080;"><strong>-</strong></span><span style="color: #800000; "><strong>1</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #0000FF;"><strong>THEN</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #FF00FF;"><strong>DATALENGTH</strong></span><span style="color: #000000;"><strong>(st.</strong></span><span style="color: #0000FF;"><strong>text</strong></span><span style="color: #000000;"><strong>)<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</strong></span><span style="color: #0000FF;"><strong>ELSE</strong></span><span style="color: #000000;"><strong>&#160;qs.statement_end_offset&#160;</strong></span><span style="color: #0000FF;"><strong>END</strong></span><span style="color: #000000;"><strong>&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</strong></span><span style="color: #808080;"><strong>-</strong></span><span style="color: #000000;"><strong>&#160;qs.statement_start_offset)</strong></span><span style="color: #808080;"><strong>/</strong></span><span style="color: #800000; "><strong>2</strong></span><span style="color: #000000;"><strong>)&#160;</strong></span><span style="color: #808080;"><strong>+</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #800000; "><strong>1</strong></span><span style="color: #000000;"><strong>)&#160;N</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>执行语句</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
</strong>
</span><span style="color: #0000FF;"><strong>FROM</strong></span><span style="color: #000000;"><strong>&#160;sys.dm_exec_query_stats&#160;</strong></span><span style="color: #0000FF;"><strong>AS</strong></span><span style="color: #000000;"><strong>&#160;qs<br />
</strong>
</span><span style="color: #0000FF;"><strong>CROSS</strong></span><span style="color: #000000;"><strong>&#160;APPLY&#160;sys.dm_exec_sql_text(qs.sql_handle)&#160;st<br />
</strong>
</span><span style="color: #0000FF;"><strong>where</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #FF00FF;"><strong>SUBSTRING</strong></span><span style="color: #000000;"><strong>(st.</strong></span><span style="color: #0000FF;"><strong>text</strong></span><span style="color: #000000;"><strong>,&#160;(qs.statement_start_offset</strong></span><span style="color: #808080;"><strong>/</strong></span><span style="color: #800000; "><strong>2</strong></span><span style="color: #000000;"><strong>)&#160;</strong></span><span style="color: #808080;"><strong>+</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #800000; "><strong>1</strong></span><span style="color: #000000;"><strong>,<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;((</strong></span><span style="color: #FF00FF;"><strong>CASE</strong></span><span style="color: #000000;"><strong>&#160;statement_end_offset&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</strong></span><span style="color: #0000FF;"><strong>WHEN</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #808080;"><strong>-</strong></span><span style="color: #800000; "><strong>1</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #0000FF;"><strong>THEN</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #FF00FF;"><strong>DATALENGTH</strong></span><span style="color: #000000;"><strong>(st.</strong></span><span style="color: #0000FF;"><strong>text</strong></span><span style="color: #000000;"><strong>)<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</strong></span><span style="color: #0000FF;"><strong>ELSE</strong></span><span style="color: #000000;"><strong>&#160;qs.statement_end_offset&#160;</strong></span><span style="color: #0000FF;"><strong>END</strong></span><span style="color: #000000;"><strong>&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</strong></span><span style="color: #808080;"><strong>-</strong></span><span style="color: #000000;"><strong>&#160;qs.statement_start_offset)</strong></span><span style="color: #808080;"><strong>/</strong></span><span style="color: #800000; "><strong>2</strong></span><span style="color: #000000;"><strong>)&#160;</strong></span><span style="color: #808080;"><strong>+</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #800000; "><strong>1</strong></span><span style="color: #000000;"><strong>)&#160;</strong></span><span style="color: #808080;"><strong>not</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #808080;"><strong>like</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #FF0000;"><strong>%fetch%</strong></span><span style="color: #FF0000;"><strong>'</strong></span><span style="color: #000000;"><strong><br />
</strong>
</span><span style="color: #0000FF;"><strong>ORDER</strong></span><span style="color: #000000;"><strong>&#160;</strong></span><span style="color: #0000FF;"><strong>BY</strong></span><span style="color: #000000;"><strong>&#160;&#160;total_elapsed_time&#160;</strong></span><span style="color: #808080;"><strong>/</strong></span><span style="color: #000000;"><strong>&#160;execution_count&#160;</strong></span><span style="color: #0000FF;"><strong>DESC</strong></span><span style="color: #000000;"><strong>;</strong></span></div>
</span></font></p>
<p>&nbsp;</p><img src ="http://www.cnblogs.com/zohong/aggbug/1324335.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43607/" target="_blank">[新闻]后“开放”平台时代</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>[转]SQL Server DBCC命令</title><link>http://www.cnblogs.com/zohong/archive/2008/11/01/1324262.html</link><dc:creator>二把刀</dc:creator><author>二把刀</author><pubDate>Sat, 01 Nov 2008 07:05:00 GMT</pubDate><guid>http://www.cnblogs.com/zohong/archive/2008/11/01/1324262.html</guid><wfw:comment>http://www.cnblogs.com/zohong/comments/1324262.html</wfw:comment><comments>http://www.cnblogs.com/zohong/archive/2008/11/01/1324262.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zohong/comments/commentRss/1324262.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zohong/services/trackbacks/1324262.html</trackback:ping><description><![CDATA[<span style="color: #333333; font-family: Arial; font-size: 12px; line-height: 18px; ">
<div id="xspace-showmessage" class="xspace-itemmessage" style="word-break: break-all; margin-right: auto; margin-left: auto; margin-top: 0.5em; margin-bottom: 0.5em; width: 99%; overflow-x: auto; overflow-y: hidden; line-height: 1.8em; ">
<p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "><strong>◆</strong><strong style="word-break: break-all; line-height: normal !important; ">1.DBCC CacheStats ：</strong><strong>显示存在于当前 buffer Cache 中的对象的信息，例如 ：hitrates&#160;编译的对象和执行计划</strong></p>
<p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "></p>
<table cellspacing="0" cellpadding="6" width="95%" align="center" border="0" style="table-layout: fixed; word-break: break-all; line-height: normal; ">
    <tbody style="word-break: break-all; line-height: normal; ">
        <tr style="word-break: break-all; line-height: normal; ">
            <td bgcolor="#f3f3f3" style="word-wrap: break-word; word-break: break-all; line-height: normal; ">DBCC&#160;CACHESTATS</td>
        </tr>
    </table>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "></p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　从这个命令可以得到一些关键的统计信息：</p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Hit Ratio：显示特定对象可以在Sql Server的缓存中被命中的百分比，这个数值越大，越好</p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Object Count：显示特定类型的对象在sql server的缓存中被命中的总数</p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Avg.Cost:sql server用于测量编译一个执行计划所需的时间，以及这个计划所需的内存。根据这个值，可以决定执行计划是否应该加载在缓存中。</p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Avg.Pages：测量在缓存中的对象使用8K页的平均总数</p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　LW Ojbect Count，LW Avg Cost，WL Avg Stay，LW Ave Use：这些列的值表明有多少特定的对象已经被写进进程从缓存总移走。这些数值越低，越好。</p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">◆<strong style="word-break: break-all; line-height: normal !important; ">2.DBCC DROPCLEANBUFFERS：</strong><strong>从缓冲池中删除所有，清除缓冲区</strong>。</p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">&#160;&#160; &#160;&#160;<span class="Apple-tab-span" style="white-space:pre">	</span>在进行测试时，使用这个命令可以从sql server&#8217;s的数据缓存data catch(buffer)清除所有的测试数据，以保证测试的公正性。需要注意的是这个命令只移走干净的缓存，不移走脏缓存。由于这个原因，在执行这个命令前，应该先执行CheckPoint，将所有脏的缓存写入磁盘，这样在运行DBCC RROPCLEANBUFFERS 时，可以保证所有的数据缓存被清理，而不是其中的一部分。</p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">◆<strong style="word-break: break-all; line-height: normal !important; ">3.DBCC ErrorLog ：</strong>如果很少重起mssqlserver服务，那么服务器的日志会增长得很快，而且打开和查看日志的速度也会很慢。使用这个命令，可以截断当前的服务器日志，主要是生成一个新的日志。可以考虑设置一个调度任务，每周执行这个命令自动截断服务器日志。使用存储过程sp_cycle_errorlog也可以达到同样的目的。</p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "><strong>◆</strong><strong style="word-break: break-all; line-height: normal !important; ">4.DBCC FLUSHPROCINDB:</strong><strong>用于清理一个数据库实例中指定数据库的存储过程使用的缓存。数据库的ID是必输参数</strong></p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">&#160;&#160; &#160;&#160;<span class="Apple-tab-span" style="white-space:pre">	</span>在测试时保证以前的存储过程计划不会对测试结果造成负面影响，可以使用这个存储过程。</p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　例：</p>
    <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "></p>
    <table cellspacing="0" cellpadding="6" width="95%" align="center" border="0" style="table-layout: fixed; word-break: break-all; line-height: normal; ">
        <tbody style="word-break: break-all; line-height: normal; ">
            <tr style="word-break: break-all; line-height: normal; ">
                <td bgcolor="#f3f3f3" style="word-wrap: break-word; word-break: break-all; line-height: normal; ">DECLARE&#160;@intDBID&#160;INTEGER&#160;SET&#160;@intDBID&#160;=&#160;(select dbid from master.dbo.sysdatabases where name&#160;=&#160;'database_name')<br style="word-break: break-all; line-height: normal; " />
                DBCC&#160;FLUSHPROCINDB&#160;(@intDBID)</td>
            </tr>
        </table>
        <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "></p>
        <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "><strong>◆</strong><strong style="word-break: break-all; line-height: normal !important; ">5.DBCC FREEPROCCACHE：</strong><strong>用于清理所有数据库的过程高速缓存。</strong></p>
        <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">&#160;&#160; &#160;&#160;<span class="Apple-tab-span" style="white-space:pre">	</span>例如，释放过程高速缓存将导致重新编译某些部分(例如特别 SQL 语句)，而不是从高速缓存中对其再使用</p>
        <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "><strong>◆</strong><strong style="word-break: break-all; line-height: normal !important; ">6.DBCC MEMORYSTATUS：</strong><strong>列出一个详细分类，分类中显示sql server缓存如何分配，包括缓存的活动.</strong>详情参见<a href="http://support.microsoft.com/kb/907877">http://support.microsoft.com/kb/907877</a></p>
        <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "><strong>◆</strong><strong style="word-break: break-all; line-height: normal !important; ">7.DBCC PAGE：</strong><strong>用于查看sql server 中一个数据页的内容</strong></p>
        <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "></p>
        <table cellspacing="0" cellpadding="6" width="95%" align="center" border="0" style="table-layout: fixed; word-break: break-all; line-height: normal; ">
            <tbody style="word-break: break-all; line-height: normal; ">
                <tr style="word-break: break-all; line-height: normal; ">
                    <td bgcolor="#f3f3f3" style="word-wrap: break-word; word-break: break-all; line-height: normal; ">DBCC&#160;PAGE((dbid|dbname)，pagenum&#160;[,Print&#160;Option][,cache][,logical])</td>
                </tr>
            </table>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "></p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　参数说明：</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Dbid or dbname ：可以是数据库ID或数据库名。</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　PageNum：要检查的页号</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Print option：(可选)打印选项的值是：0，1，2。</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　0-(缺省)显示页的头信息</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　1- 显示页的头信息，页中每行的信息以及页的偏移表。逐行显示页中的行。</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　2- 与选项1相同，除了不是逐行显示页行，而是显示一个单个的信息块。</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Cache：(可选)该参数的值是1或0，</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　0- 命令直接从磁盘查找页号而不是检查页号是否在高速缓存中DBCC PAGE</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　1- 若页在高速缓存中，优先从高速缓存中获取页，而不是直接从磁盘中获取页</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Logical：(可选)该参数用于页号是从虚拟页中获取还是逻辑页中获取。这个参数的值可以是1或0，</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　0- 一个虚拟页号</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　1- 一个逻辑页号</p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "><strong>◆</strong><strong style="word-break: break-all; line-height: normal !important; ">8.DBCC SQLMGRSTATS：</strong><strong>用于产生3个不同的值，这些值用在你想查看高速缓存在ad-hoc和预编译的</strong><a class="bluekey" href="http://whatis.ctocio.com.cn/searchwhatis/354/6092854.shtml" target="_bank" style="word-break: break-all; color: #000000; line-height: normal !important; text-decoration: underline; "><font color="#16387c" style="word-break: break-all; line-height: normal !important; "><strong>TSQL</strong></font></a><strong>语句中是如何工作的</strong></p>
            <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "></p>
            <table cellspacing="0" cellpadding="6" width="95%" align="center" border="0" style="table-layout: fixed; word-break: break-all; line-height: normal; ">
                <tbody style="word-break: break-all; line-height: normal; ">
                    <tr style="word-break: break-all; line-height: normal; ">
                        <td bgcolor="#f3f3f3" style="word-wrap: break-word; word-break: break-all; line-height: normal; ">DBCC&#160;SQLMGRSTATS</td>
                    </tr>
                </table>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "></p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　执行结果中：</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "></p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Memor Used(8K Pages)：若内存页的数量非常大，这也许是个提示：表明一些用户连接正在预处理许多TSQL语句。</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Number CSql Objects：表明已经在高速缓存中的TSQL的语句的总数</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Number False Hits：有时，当sql server&#160;在匹配在高速缓存中已经存在的TSQL语句时会出现错误的命中。在理想的情况下，这个数字应该尽可能地小。</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "><strong>◆</strong><strong style="word-break: break-all; line-height: normal !important; ">9.DBCC SQLPERF()：</strong><strong>这个命令包括了那些有文档说明和没有说明的选项</strong></p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　DBCC SQLPERF ( LOGSPACE )</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　提供有关所有数据库中的事务日志空间使用情况的统计信息。具体说明可参考联机帮助。</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　DBCC SQLPERF(UMSSTATS)：提供有关sql server线程管理情况的统计信息</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　以下是一些关键统计信息的解释：</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "></p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Scheduler ID：每个CPU对应一个调度程序，这是调度程序的序号</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Num user：目前在调度队列中的SQL Server线程数目</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Num runnable: 目前正在运行的SQL Server线程数目</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Num Workers：线程池的大小</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Idle workers：正在空闲的workers。</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　Cntxt switches：在可执行的线程之间交换上下文的数目</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　DBCC SQLPERF(WAITSTATS)：提供有关sql server read-ahead activity的信息</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　DBCC SQLOERF(IOSTATS)：提供主要的SQL server读和写的信息</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　DBCC SQLPERF(RASTATS)：提供SQL server read-ahead 活动的信息</p>
                <p style="word-break: break-all; line-height: 1.8em !important; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">　　DBCC SQLPERF (THREADS)：提供每个sql server线程的 I/O，CPU及内存使用情况的信息。</p>
                </div>
                </span><img src ="http://www.cnblogs.com/zohong/aggbug/1324262.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43607/" target="_blank">[新闻]后“开放”平台时代</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>转载  SQL Server 全局变量 </title><link>http://www.cnblogs.com/zohong/archive/2008/08/20/1272515.html</link><dc:creator>二把刀</dc:creator><author>二把刀</author><pubDate>Wed, 20 Aug 2008 11:05:00 GMT</pubDate><guid>http://www.cnblogs.com/zohong/archive/2008/08/20/1272515.html</guid><wfw:comment>http://www.cnblogs.com/zohong/comments/1272515.html</wfw:comment><comments>http://www.cnblogs.com/zohong/archive/2008/08/20/1272515.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zohong/comments/commentRss/1272515.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zohong/services/trackbacks/1272515.html</trackback:ping><description><![CDATA[@@SERVERNAME : 返回运行SQL Server 2000本地服务器的名称。 <br />
@@REMSERVER&nbsp;: 返回登录记录中记载的远程SQL Server服务器的名称。 <br />
@@CONNECTIONS : 返回自上次启动SQL Server以来连接或试图连接的次数，用其可让管理人员方便地了解今天所有试图连接服务器的次数。 <br />
@@CURSOR_ROWS : 返回最后连接上并打开的游标中当前存在的合格行的数量。 <br />
@@ERROR : 返回最后执行的Transact-SQL语句的错误代码。 <br />
@@ROWCOUNT : 返回受上一语句影响的行数，任何不返回行的语句将这一变量设置为0。 <br />
@@VERSION : 返回SQL Server当前安装的日期、版本和处理器类型。 <br />
@@CPU_BUSY : 返回自SQL Server最近一次启动以来CPU的工作时间其单位为毫秒。 <br />
@@DATEFIRST : 返回使用SET DATEFIRST命令而被赋值的DATAFIRST参数值。SET DATEFIRST命令用来指定每周的第一天是星期几。 <br />
@@DBTS : 返回当前数据库的时间戳值必须保证数据库中时间戳的值是惟一的。 <br />
@@FETCH_STATUS : 返回上一次FETCH语句的状态值。 <br />
@@IDENTITY : 返回最后插入行的标识列的列值。 <br />
@@IDLE : 返回自SQL Server最近一次启动以来CPU处于空闭状态的时间长短，单位为毫秒。 <br />
@@IO_BUSY : 返回自SQL Server最后一次启动以来CPU执行输入输出操作所花费的时间(毫秒)。 <br />
@@LANGID : 返回当前所使用的语言ID值。 <br />
@@LANGUAGE : 返回当前使用的语言名称。 <br />
@@LOCK_TIMEOUT : 返回当前会话等待锁的时间长短其单位为毫秒。 <br />
@@MAX_CONNECTIONS : 返回允许连接到SQL Server的最大连接数目。 <br />
@@MAX_PRECISION : 返回decimal 和 numeric数据类型的精确度。 <br />
@@NESTLEVEL&nbsp;: 返回当前执行的存储过程的嵌套级数，初始值为0。 <br />
@@OPTIONS : 返回当前SET选项的信息。 <br />
@@PACK_RECEIVED : 返回SQL Server通过网络读取的输入包的数目。 <br />
@@PACK_SENT : 返回SQL Server写给网络的输出包的数目。 <br />
@@PACKET_ERRORS : 返回网络包的错误数目。 <br />
@@PROCID : 返回当前存储过程的ID值。 <br />
@@SERVICENAME :返回SQL Server正运行于哪种服务状态之下：如 MS SQLServer、MSDTC、SQLServerAgent。 @@SPID : 返回当前用户处理的服务器处理ID值。 <br />
@@TEXTSIZE : 返回SET语句的TEXTSIZE选项值SET语句定义了SELECT语句中text或image。数据类型的最大长度基本单位为字节。 <br />
@@TIMETICKS : 返回每一时钟的微秒数。 <br />
@@TOTAL_ERRORS&nbsp; : 返回磁盘读写错误数目。 <br />
@@TOTAL_READ&nbsp; : 返回磁盘读操作的数目。 <br />
@@TOTAL_WRITE : 返回磁盘写操作的数目。 <br />
@@TRANCOUNT : 返回当前连接中处于激活状态的事务数目。&nbsp;&nbsp;
<img src ="http://www.cnblogs.com/zohong/aggbug/1272515.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43606/" target="_blank">[新闻]李彦宏首次表态竞价排名问题:有错能改善莫大焉</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title> 翻译 一些很酷的.Net技巧</title><link>http://www.cnblogs.com/zohong/archive/2008/07/24/1250648.html</link><dc:creator>二把刀</dc:creator><author>二把刀</author><pubDate>Thu, 24 Jul 2008 08:28:00 GMT</pubDate><guid>http://www.cnblogs.com/zohong/archive/2008/07/24/1250648.html</guid><wfw:comment>http://www.cnblogs.com/zohong/comments/1250648.html</wfw:comment><comments>http://www.cnblogs.com/zohong/archive/2008/07/24/1250648.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zohong/comments/commentRss/1250648.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zohong/services/trackbacks/1250648.html</trackback:ping><description><![CDATA[摘要: 一．.Net Framework1．如何获得系统文件夹使用System.Envioment类的GetFolderPath方法；例如：Environment.GetFolderPath( Environment.SpecialFolder.Personal )2．如何获得正在执行的exe文件的路径1）使用Application类的ExecutablePath属性2）System.Reflection&nbsp;&nbsp;<a href='http://www.cnblogs.com/zohong/archive/2008/07/24/1250648.html'>阅读全文</a><img src ="http://www.cnblogs.com/zohong/aggbug/1250648.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43605/" target="_blank">[新闻]杨致远发表博客解释辞职原因</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>【转】CLR怎样实现虚方法的多态调用（2）</title><link>http://www.cnblogs.com/zohong/articles/1157999.html</link><dc:creator>二把刀</dc:creator><author>二把刀</author><pubDate>Thu, 17 Apr 2008 06:11:00 GMT</pubDate><guid>http://www.cnblogs.com/zohong/articles/1157999.html</guid><wfw:comment>http://www.cnblogs.com/zohong/comments/1157999.html</wfw:comment><comments>http://www.cnblogs.com/zohong/articles/1157999.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zohong/comments/commentRss/1157999.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zohong/services/trackbacks/1157999.html</trackback:ping><description><![CDATA[转自：http://www.cnblogs.com/blusehuang/archive/2007/08/03/841707.html<br />
<br />
在上一篇文章<a href="http://www.cnblogs.com/blusehuang/archive/2007/07/27/833593.html">CLR怎样实现虚方法的多态调用（1）</a>中主要介绍了CLR怎样多态调用虚方法以及各种类型的方法在Method Table中的排布，但是没有介绍怎样调用接口方法，当某个对象向上转型为接口时进行多态调用时，CLR是怎样实现的呢？以下面这段代码为例来说明：
<pre><span style="color: #0000ff;">namespace</span> Demo<br />
{<br />
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">interface</span> <span style="color: #008080;">IFoo<br />
</span>    {<br />
<span style="color: #0000ff;">void</span> Foo();<br />
}<br />
<br />
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> <span style="color: #008080;">Base</span> : <span style="color: #008080;">IFoo<br />
</span>    {<br />
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> Foo()<br />
{<br />
<span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"In base's Foo function"</span>);<br />
}<br />
}<br />
<br />
<br />
<span style="color: #0000ff;">class</span> <span style="color: #008080;">Program<br />
</span>    {<br />
<span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> Main(<span style="color: #0000ff;">string</span>[] args)<br />
{<br />
<span style="color: #008080;">IFoo</span> i = <span style="color: #0000ff;">new</span> <span style="color: #008080;">Base</span>();<br />
i.Foo();<br />
}<br />
}<br />
}</pre>
<p>&nbsp; 在Essential .NET中，Don
Box向读者简单描述了基于接口的多态调用，在堆中有一个全局接口映射表，当某个类实现了一个接口，就会在这个接口表中增加项，而增加的这些项又指向这个
具体类的Method Table中的Method，可能说的不是太清楚，就用个图来表示：</p>
<p><a href="http://www.cnblogs.com/images/cnblogs_com/blusehuang/WindowsLiveWriter/72e0ae15013d_A066/image_1.png" atomicselection="true"><img style="border: 0px none ;" alt="image" src="http://www.cnblogs.com/images/cnblogs_com/blusehuang/WindowsLiveWriter/72e0ae15013d_A066/image_thumb_1.png" border="0" height="488" width="835" /></a> </p>
<p>&nbsp;当进行方法调用的时候，首先通过对象找到该类型的Method Table，根据偏移量找到指向Interface Offset
Table的指针来定位这个Interface Offset Table，然后CLR查找调用方法在这个Offset
Table的偏移量，最后调用该方法。调用的汇编代码如下：</p>
<p>&nbsp;mov ecx, esi&nbsp; -- 保存对象地址到ecx中</p>
<p>&nbsp;mov eax, dword ptr [ecx] --&nbsp;把类型的Method Table的地址保存在eax中</p>
<p>&nbsp;mov eax, dword ptr [eax+0ch] -- 把Interface Offset Table的地址保存在eax中</p>
<p>&nbsp;mov eax, dword ptr [eax + interface offset] -- 根据Interface在Table中的偏移量，找到其地址并保存到eax中</p>
<p>&nbsp;call dword ptr [eax +&nbsp; method offset] -- 根据该方法的偏移量定位改方法进行调用</p>
<p>可以说这样的调用逻辑是很清楚容易让人理解的。</p>
<p>但是当我用windbg进行跟踪的时候却发现接口方法调用机制和上面所说的不同，并没有一个查找Interface Offset Table的过程，在Main函数里是这样的调用：</p>
<p>&nbsp;mov ecx, esi --&nbsp; 保存对象地址到ecx中</p>
<p>&nbsp;call dword ptr ds:[980010h]&nbsp; 在数据段980010h上保存的是一个指针，实际上调用的是：</p>
<p>&nbsp;jmp&nbsp;mscorwks!ResolveWorkerAsmStub</p>
<p>&nbsp;可以看到跳转到ResolveWorkerAsmStub函数里去了。而这个函数是做什么的呢，下面的代码是从SSCLI里面找到的（有兴趣的可以看看<a href="http://www.krugle.com/examples/p-yqGFS82PzCP7BJSh/virtualcallstubcpu.hpp" target="_blank">virtualcallstubcpu.hpp</a>）：</p>
<pre>__declspec (naked) void ResolveWorkerAsmStub()</pre>
<p>{</p>
<p>// 首先保存寄存器状态</p>
<pre>call VirtualCallStubManager::ResolveWorkerStatic //调用ResolveWorkerStatic方法</pre>
<pre>//还原寄存器状态</pre>
<pre>jmp eax //eax保存着实际上要调用的方法的地址，所以这里就开始了方法调用</pre>
<p>}</p>
<p>所以猜想到在VirtualCallStubManager::ResolveWorkerStatic函数里面正确找到了方法的地址，保存在eax里。</p>
<p>看来到底是怎样取到该方法地址这个问题只能等下次有时间再用windbg跟踪。如果有人了解，也希望能解释一下来帮助我解答疑惑。</p>
<img src ="http://www.cnblogs.com/zohong/aggbug/1157999.html?type=2" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43604/" target="_blank">[新闻]微软公布免费安全软件计划</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>【转】CLR怎样实现虚方法的多态调用（1）</title><link>http://www.cnblogs.com/zohong/articles/1157993.html</link><dc:creator>二把刀</dc:creator><author>二把刀</author><pubDate>Thu, 17 Apr 2008 06:10:00 GMT</pubDate><guid>http://www.cnblogs.com/zohong/articles/1157993.html</guid><wfw:comment>http://www.cnblogs.com/zohong/comments/1157993.html</wfw:comment><comments>http://www.cnblogs.com/zohong/articles/1157993.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zohong/comments/commentRss/1157993.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zohong/services/trackbacks/1157993.html</trackback:ping><description><![CDATA[转自：http://www.cnblogs.com/blusehuang/archive/2007/08/03/841707.html<br />
<br />
最近一直对.net framework中，虚方法的调用是如何实现这个问题有些疑惑，在看了Essential .Net关于Method的那一章和<a href="http://artech.cnblogs.com/" target="_blank">Artech</a>推荐的文章<a href="http://msdn.microsoft.com/msdnmag/issues/05/05/JITCompiler/default.aspx" target="_blank">Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects</a>以后，还是一知半解，有些疑惑得不到答案。主要有这些：
<ul>
    <li>&nbsp; 父类定义的非虚方法是否在子类中有拷贝？
    </li>
    <li>&nbsp; 虚方法是如何实现多态的？
    </li>
    <li>&nbsp; 子类继承父类的虚方法实现是否和继承非虚方法机制相同？
    </li>
    <li>&nbsp; 如果子类隐藏了父类的虚方法，这又是怎样实现的？</li>
</ul>
<p>&nbsp; 当然问题不止这么多，关于接口方面还有很多很多疑惑，不过时间有限，一下也没办法全部弄清楚，有时间慢慢研究。我主要使用Windbg工具来跟踪调试，关于这个工具如何使用，Google一下就会有很多了。</p>
<p>&nbsp; 这些都是我自己研究加上参考资料所得，如果有不对的地方，希望大家讨论指出。</p>
<p>&nbsp; 首先看下面这段代码：</p>
<pre> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> <span style="color: #008080;">Base<br />
</span> {<br />
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> VirtualFun1()<br />
{<br />
<span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"Base.VirtualFun1"</span>);<br />
}<br />
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> NoneVirtualFun1()<br />
{<br />
System.<span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"Base.NoneVirtualFun1"</span>);<br />
}<br />
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> VirtualFun2()<br />
{<br />
System.<span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"Base.VirtualFun2"</span>);<br />
}<br />
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> VirtualFun3()<br />
{<br />
System.<span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"Base.VirtualFun3"</span>);<br />
}<br />
}<br />
<br />
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> <span style="color: #008080;">Derived</span> : <span style="color: #008080;">Base<br />
</span> {<br />
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">override</span> <span style="color: #0000ff;">void</span> VirtualFun1()<br />
{<br />
<span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"Derived.VirtualFun1"</span>);<br />
}<br />
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> VirtualFun2()<br />
{<br />
System.<span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"Derived.VirtualFun2"</span>);<br />
}<br />
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> VirtualFun4()<br />
{<br />
System.<span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"Derived.VirtualFun4"</span>);<br />
}<br />
}<br />
</pre>
<p>Base类是基类，它包含三个虚方法VirtualFun1, VirtuaFun2, VirtualFun3和一个非虚方法NoneVirtualFun1。</p>
<p>Derived继承Base类，它重写了VirtualFun1虚方法，隐藏了Base类的VirtualFun2虚方法，然后又增加了VirtualFun4虚方法。</p>
<p>看看一个Base类的实例在内存中是怎样排布的：</p>
<p><a href="http://www.cnblogs.com/images/cnblogs_com/blusehuang/WindowsLiveWriter/029e4aa7839f_9D15/image_3.png" atomicselection="true"><img style="border: 0px none ;" alt="image" src="http://www.cnblogs.com/images/cnblogs_com/blusehuang/WindowsLiveWriter/029e4aa7839f_9D15/image_thumb_3.png" border="0" height="507" width="784" /></a> </p>
<p>&nbsp; Object Ref表示某Base实例的引用，它指向在GC
Heap中分配的Base对象，这个对象可以分为三部分：同步块索引、类型指针和字段。主要来关注类型指针，它指向该类型的Method
Table，这其实是在Load Heap中分配的Type类型对象，所有该类型的实例的类型指针都指向同一个Method
Table（这里表示所有Base对象的类型指针都指向同一个Method Table）。</p>
<p>&nbsp; Method Table里面包含很多信息，这里关注有关Method这一区域，（如果想了解更详细的method table，请参考上面的文章）。</p>
<p>&nbsp; 根据在Method
Table里的信息，可以知道它包含9个Method（其实应该有个字段标示有多少个虚方法，这里就没画了）。接下来就是这些method，它分为两部
分，前面一部分是所有的虚方法，后面的是非虚方法。因为所有的类型都是继承自System.Object类，所以前四个方法是Object类的虚方法
（ToString, Equals, GetHashCode, Finalize），接着是Base类定义的三个虚方法（VirtualFun1,
VirtualFun2,
VirtualFun3），最后是Base类的非虚方法NoneVirtualFun1以及默认的构造函数。下面再来看看Derived类型的
Method Table：</p>
<p><a href="http://www.cnblogs.com/images/cnblogs_com/blusehuang/WindowsLiveWriter/029e4aa7839f_9D15/image_6.png" atomicselection="true"><img style="border: 0px none ;" alt="image" src="http://www.cnblogs.com/images/cnblogs_com/blusehuang/WindowsLiveWriter/029e4aa7839f_9D15/image_thumb_6.png" border="0" height="558" width="788" /></a> </p>
<p>仔细对比一下这两个Method Table，可以发现这样几个特点：</p>
<ul>
    <li>Base类中的所有虚方法在Derived类的Method Table中一一对应
    </li>
    <li>Base类中的所有非虚方法在Derived类中的Method Table并没有拷贝（这一点回答了上面的第一个问题）
    </li>
    <li>Derived类新增的虚方法都添加到继承自Base类的虚方法的后面
    </li>
    <li>如果Derived类override Base类的虚方法，它就将该方法指向自身的实现
    </li>
    <li>如果Derived类使用new关键字隐藏了Base类虚方法的实现，它就相当于增加了一个虚方法，而不是覆盖。</li>
</ul>
<p>下面看看调用虚方法时如何实现多态，比如有这样一段代码</p>
<p>&nbsp; Base b = new Derived();</p>
<p>&nbsp;&nbsp;b.VirtualFun1(); </p>
<p>编译后在我的机器上会生成这样的汇编代码：</p>
<p>&nbsp; mov ecx, esi</p>
<p>&nbsp; mov eax, dword ptr[ecx]</p>
<p>&nbsp; call dword ptr [eax + 3ch]</p>
<p>&nbsp; 现在来解释这几句代码：mov ecx, esi 是将新构造的对象的地址保存在ecx寄存器中； mov eax, dword
ptr[ecx] 表示ecx的值是一个指针（根据上面的图可以知道对象的头4个字节保存的是method table的地址），它将method
table的地址保存到eax寄存器中，最后call dword ptr[eax +
3ch]。3ch表示偏移量，它表示该方法相对于该method table的偏址，是在该类型加载到load
heap以后确定的。这样，由method table的地址加上method相对与method table的偏移量，就可以唯一确定一个方法。</p>
<p>&nbsp; 这样在调用b.VirtualFun1(); 时，由于b是Derived类的实例，所以根据它指向的托管对象找到的method
table是Derived类型的method
table，就能正确调用该方法。因为Derived类中override了VirtualFun1这个虚方法，所以调用的是Derived类的实现，而
如果没有override基类的虚方法，它就指向基类的该方法的实现。</p>
<p>&nbsp; 由此可以看出，CLR实现虚方法的机制主要是通过类型的method table加上该虚方法相对于method
table的偏移量来确定调用具体方法的。一个虚方法在整个继承体系所有类型对应的method
table中的偏移量是固定的，比如VirtualFunc1在Base类型的method
table中的偏移量是3ch，它在Derived类型的method
table中的偏移量也是3ch，如果还有继承自Derived类的类，也是同样，利用这种机制就实现了多态。</p>
<p>&nbsp; <strong><font size="4">结论</font></strong></p>
<ul>
    <li>&nbsp; 每个类型对应一个Method Table
    </li>
    <li>&nbsp; 子类的Method Table中包含父类的所有虚方法，而不包含父类的非虚方法
    </li>
    <li>&nbsp; CLR根据对象找到它对应类型的method table，然后根据该虚方法在method table中的偏移量实现多态调用。</li>
</ul>
<img src ="http://www.cnblogs.com/zohong/aggbug/1157993.html?type=2" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43604/" target="_blank">[新闻]微软公布免费安全软件计划</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>【转】继承本质论</title><link>http://www.cnblogs.com/zohong/articles/1156501.html</link><dc:creator>二把刀</dc:creator><author>二把刀</author><pubDate>Wed, 16 Apr 2008 08:49:00 GMT</pubDate><guid>http://www.cnblogs.com/zohong/articles/1156501.html</guid><wfw:comment>http://www.cnblogs.com/zohong/comments/1156501.html</wfw:comment><comments>http://www.cnblogs.com/zohong/articles/1156501.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnblogs.com/zohong/comments/commentRss/1156501.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zohong/services/trackbacks/1156501.html</trackback:ping><description><![CDATA[<h3><span style="font-size: 12pt;"><span style="font-size: 10pt;"><span style="font-size: 8pt;"><span style="font-size: 10pt;"><span style="font-family: 宋体;">声明：转自 <a href="http://www.cnblogs.com/anytao/archive/2007/09/10/must_net_15.html">anytao.com</a></span><a href="http://www.cnblogs.com/anytao/archive/2007/09/10/must_net_15.html"></a></span><a href="http://www.cnblogs.com/anytao/archive/2007/09/10/must_net_15.html"></a></span></span><a href="http://www.cnblogs.com/anytao/archive/2007/09/10/must_net_15.html"></a></span><a href="http://www.cnblogs.com/anytao/archive/2007/09/10/must_net_15.html"></a></h3>
<h3>1. 引言</h3>
<p>关于继承，你是否驾熟就轻，关于继承，你是否了如指掌。
</p>
<p>本文不讨论继承的基本概念，我们回归本质，从编译器运行的角度来揭示.NET继承中的运行本源，来发现子类对象是如何实现了对父类成员与方法的继承，以最为简陋的示例来揭示继承的实质，阐述继承机制是如何被执行的，这对于更好的理解继承，是必要且必然的。
</p>
<h3>2. 分析</h3>
<p>下面首先以一个简单的动物继承体系为例，来进行说明：
</p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top" /><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;Animal<br />
<img id="Codehighlighter1_29_138_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_29_138_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_29_138_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_29_138_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_29_138_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_29_138_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_29_138_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_29_138_Open_Text').style.display='inline';" alt="" align="top" /></span><span id="Codehighlighter1_29_138_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_29_138_Open_Text"><span style="color: rgb(0, 0, 0);">{<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;ShowType();<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" /><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;Eat()<br />
<img id="Codehighlighter1_89_136_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_89_136_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_89_136_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_89_136_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_89_136_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_89_136_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_89_136_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_89_136_Open_Text').style.display='inline';" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_89_136_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_89_136_Open_Text"><span style="color: rgb(0, 0, 0);">{<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">Animal&nbsp;always&nbsp;eat.</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: rgb(0, 0, 0);"><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" alt="" align="top" />}</span></span><span style="color: rgb(0, 0, 0);"><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top" /><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top" /></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;Bird:&nbsp;Animal<br />
<img id="Codehighlighter1_166_383_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_166_383_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_166_383_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_166_383_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_166_383_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_166_383_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_166_383_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_166_383_Open_Text').style.display='inline';" alt="" align="top" /></span><span id="Codehighlighter1_166_383_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_166_383_Open_Text"><span style="color: rgb(0, 0, 0);">{<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">&nbsp;type&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">Bird</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;ShowType()<br />
<img id="Codehighlighter1_234_280_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_234_280_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_234_280_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_234_280_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_234_280_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_234_280_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_234_280_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_234_280_Open_Text').style.display='inline';" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_234_280_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_234_280_Open_Text"><span style="color: rgb(0, 0, 0);">{<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">Type&nbsp;is&nbsp;{0}</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,&nbsp;type);<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: rgb(0, 0, 0);"><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" /><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">&nbsp;color;<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">&nbsp;Color<br />
<img id="Codehighlighter1_328_381_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_328_381_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_328_381_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_328_381_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_328_381_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_328_381_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_328_381_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_328_381_Open_Text').style.display='inline';" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_328_381_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_328_381_Open_Text"><span style="color: rgb(0, 0, 0);">{<br />
<img id="Codehighlighter1_336_353_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_336_353_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_336_353_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_336_353_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_336_353_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_336_353_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_336_353_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_336_353_Open_Text').style.display='inline';" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">get</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span id="Codehighlighter1_336_353_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_336_353_Open_Text"><span style="color: rgb(0, 0, 0);">{&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;color;&nbsp;}</span></span><span style="color: rgb(0, 0, 0);"><br />
<img id="Codehighlighter1_360_378_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_360_378_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_360_378_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_360_378_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_360_378_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_360_378_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_360_378_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_360_378_Open_Text').style.display='inline';" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">set</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span id="Codehighlighter1_360_378_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_360_378_Open_Text"><span style="color: rgb(0, 0, 0);">{&nbsp;color&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;value;&nbsp;}</span></span><span style="color: rgb(0, 0, 0);"><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: rgb(0, 0, 0);"><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" alt="" align="top" />}</span></span><span style="color: rgb(0, 0, 0);"><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top" /><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top" /></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;Chicken&nbsp;:&nbsp;Bird<br />
<img id="Codehighlighter1_413_608_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_413_608_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_413_608_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_413_608_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_413_608_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_413_608_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_413_608_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_413_608_Open_Text').style.display='inline';" alt="" align="top" /></span><span id="Codehighlighter1_413_608_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_413_608_Open_Text"><span style="color: rgb(0, 0, 0);">{<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">&nbsp;type&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">Chicken</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;ShowType()<br />
<img id="Codehighlighter1_484_530_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_484_530_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_484_530_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_484_530_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_484_530_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_484_530_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_484_530_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_484_530_Open_Text').style.display='inline';" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_484_530_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_484_530_Open_Text"><span style="color: rgb(0, 0, 0);">{<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">Type&nbsp;is&nbsp;{0}</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,&nbsp;type);<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: rgb(0, 0, 0);"><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" /><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;ShowColor()<br />
<img id="Codehighlighter1_558_606_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_558_606_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_558_606_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_558_606_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_558_606_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_558_606_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_558_606_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_558_606_Open_Text').style.display='inline';" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_558_606_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_558_606_Open_Text"><span style="color: rgb(0, 0, 0);">{<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">Color&nbsp;is&nbsp;{0}</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,&nbsp;Color);<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: rgb(0, 0, 0);"><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" alt="" align="top" />}</span></span></div>
<p>然后，在测试类中创建各个类对象，由于Animal为抽象类，我们只创建Bird对象和Chicken对象。
</p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top" /><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;TestInheritance<br />
<img id="Codehighlighter1_29_126_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_29_126_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_29_126_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_29_126_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_29_126_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_29_126_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_29_126_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_29_126_Open_Text').style.display='inline';" alt="" align="top" /></span><span id="Codehighlighter1_29_126_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_29_126_Open_Text"><span style="color: rgb(0, 0, 0);">{<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;Main()<br />
<img id="Codehighlighter1_59_124_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_59_124_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_59_124_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_59_124_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_59_124_Closed_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_59_124_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_59_124_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_59_124_Open_Text').style.display='inline';" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_59_124_Closed_Text" style="border: 1px solid rgb(128, 128, 128); background-color: rgb(255, 255, 255); display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_59_124_Open_Text"><span style="color: rgb(0, 0, 0);">{<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bird&nbsp;bird&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Bird();<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Chicken&nbsp;chicken&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Chicken();<br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: rgb(0, 0, 0);"><br />
<img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" alt="" align="top" />}</span></span></div>
<p>下面我们从编译角度对这一简单的继承示例进行深入分析，从而了解.NET内部是如何实现我们强调的继承机制。
</p>
<p>（1）我们简要的分析一下对象的创建过程：
</p>
&nbsp;&nbsp;&nbsp; Bird animal = new Bird();
<p>Bird bird创建的是一个Bird类型的引用，而new Bird()完成的是创建Bird对象，分配内存空间和初始化操作，然后将这个对象赋给bird引用，也就是建立bird引用与Bird对象的关联。
</p>
<p>（2）我们从继承的角度来分析在编译器编译期是如何执行对象的创建过程，因为继承的本质就体现于对象的创建过程。
</p>
<p>在此我们以Chicken对象的创建为例，首先是字段，对象一经创建，会首先找到其父类Bird，并为其字段分配存储空间，而Bird也会
继续找到其父类Animal，为其分配存储空间，依次类推直到递归结束，也就是完成System.Object内存分配为止。我们可以在编译器中单步执行
的方法来大致了解其分配的过程和顺序，因此，对象的创建过程是按照顺序完成了对整个父类及其本身字段的内存创建，并且字段的存储顺序是由上到下排列，
object类的字段排在最前面，其原因是如果父类和子类出现了同名字段，则在子类对象创建时，编译器会自动认为这是两个不同的字段而加以区别。
</p>
<p>然后，是方法表的创建，必须明确的一点是方法表的创建是类第一次加载到CLR时完成的，在对象创建时只是将其附加成员TypeHandle指向方法列表在Loader Heap上的地址，将对象与其动态方法列表相关联起来，因此方法表是先于对象而存在的。类似于字段的创建过程，方法表的创建也是父类在先子类在后，原因是显而易见的，类Chicken生成方法列表时，首先将Bird的所有方法拷贝一份，然后和Chicken本身的方法列表做以对比，如果有覆写的虚方法则以子类方法覆盖同名的父类方法，同时添加子类的新方法，从而创建完成Chicken的方法列表。这种创建过程也是逐层递归到Object类，并且方法列表中也是按照顺序排列的，父类在前子类在后，其原因和字段大同小异，留待读者自己体味。
</p>
<p>结合我们的分析过程，现在将对象创建的过程以简单的图例来揭示其在内存中的分配情形，如下：
</p>
<p align="center"><img alt="" src="http://www.cnblogs.com/images/cnblogs_com/anytao/Anytao_15_3.jpg" border="0" />&nbsp;</p>
<p>从我们的分析，和上面的对象创建过程可见，对继承的本质我们有了更明确的认识，对于以下的问题就有了清晰明白的答案：
</p>
<ul>
    <li>继承是可传递的，子类是对父类的扩展，必须继承父类方法，同时可以添加新方法。
    </li>
    <li>子类可以调用父类方法和字段，而父类不能调用子类方法和字段。
    </li>
    <li>虚方法如何实现覆写操作，使得父类指针可以指向子类对象成员。
    </li>
    <li>new关键字在虚方法继承中的阻断作用。 </li>
</ul>
<p>你是否已经找到了理解继承、理解动态编译的不二法门。
</p>
<h3>3. 思考</h3>
<p>通过上面的讲述与分析，我们基本上对.NET在编译期的实现原理有了大致的了解，但是还有以下的问题，一定会引起一定的疑惑，那就是：<br />
</p>
<p>&nbsp;&nbsp;&nbsp; Bird bird2 = new Chicken();
</p>
<p>这种情况下，bird2.ShowType应该返回什么值呢？而bird2.type有该是什么值呢？有两个原则，是.NET专门用于解决这一问题的：
</p>
<ul>
    <li><strong>关注对象原则：调用子类还是父类的方法，取决于创建的对象是子类对象还是父类对象，而不是它的引用类型。</strong>例如
    Bird bird2 = new
    Chicken()时，我们关注的是其创建对象为Chicken类型，因此子类将继承父类的字段和方法，或者覆写父类的虚方法，而不用关注bird2的引
    用类型是否为Bird。引用类型不同的区别决定了不同的对象在方法表中不同的访问权限。 </li>
</ul>
<div style="border: 1px solid rgb(102, 102, 102);">
<p>注意
</p>
<p>根据关注对象原则，那么下面的两种情况又该如何区别呢？</p>
<p>Bird bird2 = new Chicken();<br />
Chicken chicken = new Chicken();
</p>
<p>根据我们上文的分析，bird2对象和chicken对象在内存布局上是一样的，差别就在于其引用指针的类型不同：bird2为Bird类型指针，
而chicken为Chicken类型指针。以方法调用为例，不同的类型指针在虚拟方法表中有不同的附加信息作为标志来区别其访问的地址区域，称为
offset。不同类型的指针只能在其特定地址区域内进行执行，子类覆盖父类时会保证其访问地址区域的一致性，从而解决了不同的类型访问具有不同的访问权
限问题。</p>
</div>
&nbsp;
<ul>
    <li><strong>执行就近原则：对于同名字段或者方法，编译器是按照其顺序查找来引用的，也就是首先访问离它创建最近的字段或者方法</strong>，例如上
    例中的bird2，是Bird类型，因此会首先访问Bird_type（注意编译器是不会重新命名的，在此是为区分起见），如果type类型设为
    public，则在此将返回&#8220;Bird&#8221;值。这也就是为什么在对象创建时必须将字段按顺序排列，而父类要先于子类编译的原因了。 </li>
</ul>
<div style="border: 1px solid rgb(102, 102, 102);">
<p>思考
</p>
<p>1. 上面我们分析到bird2.type的值是&#8220;Bird&#8221;，那么bird2.ShowType()会显示什么值呢？答案是&#8220;Type is Chicken&#8221;，根据本文上面的分析，想想到底为什么？
</p>
<p>2. 关于new关键字在虚方法动态调用中的阻断作用，也有了更明确的理论基础。在子类方法中，如果标记new关键字，则意味着隐藏基类实现，其实就是创建了与父类同名的另一个方法，在编译中这两个方法处于动态方法表的不同地址位置，父类方法排在前面，子类方法排在后面。</p>
</div>
&nbsp;
<h3><span style="color: red;"><span style="color: rgb(0, 0, 0);">4<span style="color: rgb(0, 0, 0);">. 结论</span></span></span></h3>
在.NET中，如果创建一个类，则该类总是在继承。这缘于.NET的面向对象特性，所有的类型都最终继承自共同的根System.Object类。
可见，继承是.NET运行机制的基础技术之一，一切皆为对象，一切皆于继承。本文从基础出发，深入本质探索本源，分析疑难比较鉴别。对于什么是继承这个话
题，希望每个人能从中寻求自己的答案，理解继承、关注封装、玩转多态是理解面向对象的起点，希望本文是这一旅程的起点。
<img src ="http://www.cnblogs.com/zohong/aggbug/1156501.html?type=2" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43603/" target="_blank">[新闻]《时代》：杨致远被Google玩弄于股掌之间？</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>【转】用Coding证明Application Domain的隔离性</title><link>http://www.cnblogs.com/zohong/articles/1153949.html</link><dc:creator>二把刀</dc:creator><author>二把刀</author><pubDate>Tue, 15 Apr 2008 02:25:00 GMT</pubDate><guid>http://www.cnblogs.com/zohong/articles/1153949.html</guid><wfw:comment>http://www.cnblogs.com/zohong/comments/1153949.html</wfw:comment><comments>http://www.cnblogs.com/zohong/articles/1153949.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zohong/comments/commentRss/1153949.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zohong/services/trackbacks/1153949.html</trackback:ping><description><![CDATA[摘要: 申明:转载至artechApplicationDomain可以看作是一个Assembly的逻辑容器。在程序执行过程中，如果遇到需要的Type并没有定义在已经加载的Assemblies中，CLR会把相应的Assembly加载的该Application Domain中。每个ApplicationDomain都有一个属于自己的加载器堆（Loader Heap），用于维护从ApplicationDomai&nbsp;&nbsp;<a href='http://www.cnblogs.com/zohong/articles/1153949.html'>阅读全文</a><img src ="http://www.cnblogs.com/zohong/aggbug/1153949.html?type=2" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43602/" target="_blank">[新闻]Mozilla即将结束对FireFox 2的支持</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>【转】初识泛型编程</title><link>http://www.cnblogs.com/zohong/articles/1147063.html</link><dc:creator>二把刀</dc:creator><author>二把刀</author><pubDate>Thu, 10 Apr 2008 08:57:00 GMT</pubDate><guid>http://www.cnblogs.com/zohong/articles/1147063.html</guid><wfw:comment>http://www.cnblogs.com/zohong/comments/1147063.html</wfw:comment><comments>http://www.cnblogs.com/zohong/articles/1147063.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zohong/comments/commentRss/1147063.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zohong/services/trackbacks/1147063.html</trackback:ping><description><![CDATA[<p>在2005年底微软公司正式发布了C# 2.0，与C#
1.x相比，新版本增加了很多新特性，其中最重要的是对泛型的支持。通过泛型，我们可以定义类型安全的数据结构，而无需使用实际的数据类型。这能显著提高性能并得到更高质量的代码。泛型并不是什么新鲜的东西，他在功能上类似于C++的模板，模板多年前就已存在C++上了，并且在C++上有大量成熟应用。
<font color="#ffffff">字串8</font> </p>
<p>　　本文讨论泛型使用的一般问题，比如为什么要使用泛型、泛型的编写方法、泛型中数据类型的约束、泛型中静态成员使用要注意的问题、泛型中方法重载的问、泛型方法等，通过这些使我们可以大致了解泛型并掌握泛型的一般应用，编写出更简单、通用、高效的应用系统。
</p>
<p>　　什么是泛型
</p>
<p>　　我们在编写程序时，经常遇到两个模块的功能非常相似，只是一个是处理int数据，另一个是处理string数据，或者其他自定义的数据类型，但我们没有办法，只能分别写多个方法处理每个数据类型，因为方法的参数类型不同。有没有一种办法，在方法中传入通用的数据类型，这样不就可以合并代码了吗？泛型的出现就是专门解决这个问题的。读完本篇文章，你会对泛型有更深的了解。
</p>
<p>　　为什么要使用泛型
</p>
<p>　　为了了解这个问题，我们先看下面的代码，代码省略了一些内容，但功能是实现一个栈，这个栈只能处理int数据类型：&nbsp;<br />
</p>
<p>&nbsp;&nbsp;&nbsp; public class Stack<br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; private int[] m_item;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public int Pop(){...}
<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void Push(int item){...} <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public Stack(int
i)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.m_item = new int[i];<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; } <font color="#ffffff">字串7</font> </p>
<p>　　上面代码运行的很好，但是，当我们需要一个栈来保存string类型时，该怎么办呢？很多人都会想到把上面的代码复制一份，把int改成string不就行了。当然，这样做本身是没有任何问题的，但一个优秀的程序是不会这样做的，因为他想到若以后再需要long、Node类型的栈该怎样做呢？还要再复制吗？优秀的程序员会想到用一个通用的数据类型object来实现这个栈：
</p>
<p>&nbsp;&nbsp;&nbsp; public class Stack<br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; private object[] m_item;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public object
Pop(){...} <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void Push(object item){...} </p>
<p>　&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public Stack(int i)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.m_item = new[i];<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }
</p>
<p>　　这个栈写的不错，他非常灵活，可以接收任何数据类型，可以说是一劳永逸。但全面地讲，也不是没有缺陷的，主要表现在：
</p>
<ol>
    <li>当Stack处理值类型时，会出现装箱、折箱操作，这将在托管堆上分配和回收大量的变量，若数据量大，则性能损失非常严重。</li>
    <li>在处理引用类型时，虽然没有装箱和折箱操作，但将用到数据类型的强制转换操作，增加处理器的负担。</li>
</ol>
<p>　　在数据类型的强制转换上还有更严重的问题（假设stack是Stack的一个实例）：<font color="#ffffff"></font>
</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Node1 x = new Node1();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; stack.Push(x);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Node2 y = (Node2)stack.Pop();
</p>
<p>　　上面的代码在编译时是完全没问题的，但由于Push了一个Node1类型的数据，但在Pop时却要求转换为Node2类型，这将出现程序运行时的类型转换异常，但却逃离了编译器的检查。&nbsp;<br />
</p>
<p>　　针对object类型栈的问题，我们引入泛型，他可以优雅地解决这些问题。泛型用用一个通过的数据类型T来代替object，在类实例化时指定T的类型，运行时（Runtime）自动编译为本地代码，运行效率和代码质量都有很大提高，并且保证数据类型安全。&nbsp;<br />
</p>
<p>　　使用泛型
</p>
<p>　　下面是用泛型来重写上面的栈，用一个通用的数据类型T来作为一个占位符，等待在实例化时用一个实际的类型来代替。让我们来看看泛型的威力：
</p>
<p>&nbsp;&nbsp;&nbsp; public class Stack&lt;T&gt;<br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; private T[] m_item;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public T
Pop(){...} <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void Push(T item){...} </p>
<p>　&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public Stack(int i)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.m_item = new T[i];<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; } <br />
</p>
<p>　　类的写法不变，只是引入了通用数据类型T就可以适用于任何数据类型，并且类型安全的。这个类的调用方法：&nbsp;<font color="#ffffff"></font> </p>
<p>&nbsp;&nbsp;&nbsp; //实例化只能保存int类型的类<font color="#ffffff"></font> </p>
<p>&nbsp;&nbsp;&nbsp; Stack&lt;int&gt; a = new
Stack&lt;int&gt;(100);<br />
&nbsp;&nbsp;&nbsp; a.Push(10);<br />
&nbsp;&nbsp;&nbsp; a.Push("8888");
//这一行编译不通过，因为类a只接收int类型的数据<br />
&nbsp;&nbsp;&nbsp; int x = a.Pop();
</p>
<p>&nbsp;&nbsp;&nbsp; //实例化只能保存string类型的类
</p>
<p>&nbsp;&nbsp;&nbsp; Stack&lt;string&gt; b = new Stack&lt;string&gt;(100);<br />
&nbsp;&nbsp;&nbsp; b.Push(10);
//这一行编译不通过，因为类b只接收string类型的数据<br />
&nbsp;&nbsp;&nbsp; b.Push("8888");<br />
&nbsp;&nbsp;&nbsp; string y = b.Pop();
</p>
<p>　　这个类和object实现的类有截然不同的区别：&nbsp;<font color="#ffffff"></font> </p>
<p>　　1. 他是类型安全的。实例化了int类型的栈，就不能处理string类型的数据，其他数据类型也一样。<font color="#ffffff"></font> </p>
<p>　　2. 无需装箱和折箱。这个类在实例化时，按照所传入的数据类型生成本地代码，本地代码数据类型已确定，所以无需装箱和折箱。
</p>
<p>　　3. 无需类型转换。<font color="#ffffff"></font> </p>
<p>　　泛型类实例化的理论
</p>
<p>　　C#泛型类在编译时，先生成中间代码IL，通用类型T只是一个占位符。在实例化类时，根据用户指定的数据类型代替T并由即时编译器（JIT）生成本地代码，这个本地代码中已经使用了实际的数据类型，等同于用实际类型写的类，所以不同的封闭类的本地代码是不一样的。按照这个原理，我们可以这样认为：
</p>
<p>　　泛型类的不同的封闭类是分别不同的数据类型。
</p>
<p>　　例：Stack&lt;int&gt;和Stack&lt;string&gt;是两个完全没有任何关系的类，你可以把他看成类A和类B，这个解释对泛型类的静态成员的理解有很大帮助。
</p>
<p>　　泛型类中数据类型的约束<font color="#ffffff"></font> </p>
<p>　　程序员在编写泛型类时，总是会对通用数据类型T进行有意或无意地有假想，也就是说这个T一般来说是不能适应所有类型，但怎样限制调用者传入的数据类型呢？这就需要对传入的数据类型进行约束，约束的方式是指定T的祖先，即继承的接口或类。因为C#的单根继承性，所以约束可以有多个接口，但最多只能有一个类，并且类必须在接口之前。这时就用到了C#2.0的新增关键字：<font color="#ffffff"></font> </p>
<p>&nbsp;&nbsp;&nbsp; public class Node&lt;T, V&gt; where T : Stack, IComparable<br />
&nbsp;&nbsp;&nbsp; where V:
Stack<br />
&nbsp;&nbsp;&nbsp; {...}&nbsp;<br />
</p>
<p>　　以上的泛型类的约束表明，T必须是从Stack和IComparable继承，V必须是Stack或从Stack继承，否则将无法通过编译器的类型检查，编译失败。
</p>
<p>　　通用类型T没有特指，但因为C#中所有的类都是从object继承来，所以他在类Node的编写中只能调用object类的方法，这给程序的编写造成了困难。比如你的类设计只需要支持两种数据类型int和string，并且在类中需要对T类型的变量比较大小，但这些却无法实现，因为object是没有比较大小的方法的。
了解决这个问题，只需对T进行IComparable约束，这时在类Node里就可以对T的实例执行CompareTo方法了。这个问题可以扩展到其他用户自定义的数据类型。&nbsp;<font color="#ffffff"></font> </p>
<p>　　如果在类Node里需要对T重新进行实例化该怎么办呢？因为类Node中不知道类T到底有哪些构造函数。为了解决这个问题，需要用到new约束：
</p>
<p>&nbsp;&nbsp;&nbsp; public class Node&lt;T, V&gt; where T : Stack, new()<br />
&nbsp;&nbsp;&nbsp; where V: IComparable
</p>
<p>　　需要注意的是，new约束只能是无参数的，所以也要求相应的类Stack必须有一个无参构造函数，否则编译失败。
</p>
<p>　　C#中数据类型有两大类：引用类型和值类型。引用类型如所有的类，值类型一般是语言的最基本类型，如int, long,
struct等，在泛型的约束中，我们也可以大范围地限制类型T必须是引用类型或必须是值类型，分别对应的关键字是class和struct:
</p>
<p>&nbsp;&nbsp;&nbsp; public class Node&lt;T, V&gt; where T : class<br />
&nbsp;&nbsp;&nbsp; where V: struct
</p>
<p>　　泛型方法 </p>
<p>　　泛型不仅能作用在类上，也可单独用在类的方法上，他可根据方法参数的类型自动适应各种参数，这样的方法叫泛型方法。看下面的类： </p>
<p>&nbsp;&nbsp;&nbsp; public class Stack2<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void Push&lt;T&gt;(Stack&lt;T&gt; s,
params T[] p)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; foreach (T t in
p)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; s.Push(t);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
</p>
<p>　　原来的类Stack一次只能Push一个数据，这个类Stack2扩展了Stack的功能（当然也可以直接写在Stack中），他可以一次把多个数据压入Stack中。其中Push是一个泛型方法，这个方法的调用示例如下：&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp; Stack&lt;int&gt; x = new Stack&lt;int&gt;(100);<br />
&nbsp;&nbsp;&nbsp; Stack2 x2 = new
Stack2();<br />
&nbsp;&nbsp;&nbsp; x2.Push(x, 1, 2, 3, 4, 6);
</p>
<p>&nbsp;&nbsp;&nbsp; string s = "";
</p>
<p>&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; 5; i++)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; s += x.Pop().ToString();<br />
&nbsp;&nbsp;&nbsp; }
//至此，s的值为64321
</p>
<p>　　泛型中的静态成员变量 </p>
<p>　　在C#1.x中，我们知道类的静态成员变量在不同的类实例间是共享的，并且他是通过类名访问的。C#2.0中由于引进了泛型，导致静态成员变量的机制出现了一些变化：静态成员变量在相同封闭类间共享，不同的封闭类间不共享。
</p>
<p>　　这也非常容易理解，因为不同的封闭类虽然有相同的类名称，但由于分别传入了不同的数据类型，他们是完全不同的类，比如：
</p>
<p>&nbsp;&nbsp;&nbsp; Stack&lt;int&gt; a = new Stack&lt;int&gt;();<br />
&nbsp;&nbsp;&nbsp; Stack&lt;int&gt; b = new
Stack&lt;int&gt;();<br />
&nbsp;&nbsp;&nbsp; Stack&lt;long&gt; c = new Stack&lt;long&gt;();
</p>
<p>　　类实例a和b是同一类型，他们之间共享静态成员变量，但类实例c却是和a、b完全不同的类型，所以不能和a、b共享静态成员变量。 </p>
<p>　　泛型中的静态构造函数
</p>
<p>　　静态构造函数的规则：只能有一个，且不能有参数，他只能被.NET运行时自动调用，而不能人工调用。&nbsp;<font color="#ffffff"></font> </p>
<p>　　泛型中的静态构造函数的原理和非泛型类是一样的，只需把泛型中的不同的封闭类理解为不同的类即可。以下两种情况可激发静态的构造函数：<br />
&nbsp;&nbsp;&nbsp; 1. 特定的封闭类第一次被实例化。<br />
&nbsp;&nbsp;&nbsp; 2. 特定封闭类中任一静态成员变量被调用。</p>
<p>　　泛型类中的方法重载
</p>
<p>　　方法的重载在.Net
Framework中被大量应用，他要求重载具有不同的签名。在泛型类中，由于通用类型T在类编写时并不确定，所以在重载时有些注意事项，这些事项我们通过以下的例子说明：<font color="#ffffff"></font> </p>
<p>&nbsp;&nbsp;&nbsp; public class Node&lt;T, V&gt; <br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public T add(T a, V b)
//第一个add<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return a;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public T add(V a, T b)
//第二个add<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return b;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public int add(int a, int b)
//第三个add<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return a + b;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }
</p>
<p>　　上面的类很明显，如果T和V都传入int的话，三个add方法将具有同样的签名，但这个类仍然能通过编译，是否会引起调用混淆将在这个类实例化和调用add方法时判断。请看下面调用代码：&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp; Node&lt;int, int&gt; node = new Node&lt;int, int&gt;();<br />
&nbsp;&nbsp;&nbsp; object x =
node.add(2, 11);
</p>
<p>　　这个Node的实例化引起了三个add具有同样的签名，但却能调用成功，因为他优先匹配了第三个add。但如果删除了第三个add，上面的调用代码则无法编译通过，提示方法产生的混淆，因为运行时无法在第一个add和第二个add之间选择。
</p>
<p>&nbsp;&nbsp;&nbsp; Node&lt;string, int&gt; node = new Node&lt;string, int&gt;();<br />
&nbsp;&nbsp;&nbsp; object x =
node.add(2, "11");
</p>
<p>　　这两行调用代码可正确编译，因为传入的string和int，使三个add具有不同的签名，当然能找到唯一匹配的add方法。
</p>
<p>　　由以上示例可知，C#的泛型是在实例的方法被调用时检查重载是否产生混淆，而不是在泛型类本身编译时检查。同时还得出一个重要原则：
</p>
<p>　　当一般方法与泛型方法具有相同的签名时，会覆盖泛型方法。 </p>
<p>　　泛型类的方法重写 </p>
<p>　　方法重写（override）的主要问题是方法签名的识别规则，在这一点上他与方法重载一样，请参考泛型类的方法重载。
</p>
<p>　　泛型的使用范围
</p>
<p>　　本文主要是在类中讲述泛型，实际上，泛型还可以用在类方法、接口、结构（struct）、委托等上面使用，使用方法大致相同，就不再讲述。 </p>
<p>　　小结<br />
</p>
<p>　　C#
泛型是开发工具库中的一个无价之宝。它们可以提高性能、类型安全和质量，减少重复性的编程任务，简化总体编程模型，而这一切都是通过优雅的、可读性强的语法完成的。尽管
C# 泛型的根基是 C++ 模板，但 C# 通过提供编译时安全和支持将泛型提高到了一个新水平。C#
利用了两阶段编译、元数据以及诸如约束和一般方法之类的创新性的概念。毫无疑问，C#
的将来版本将继续发展泛型，以便添加新的功能，并且将泛型扩展到诸如数据访问或本地化之类的其他 .NET Framework 领域。&nbsp;<br />
</p>
<img src ="http://www.cnblogs.com/zohong/aggbug/1147063.html?type=2" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43601/" target="_blank">[新闻]IBM"走鹃"险胜"Cray Jaguar" 连任世界最快超级计算机</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>【转】深入剖析ASP.NET的编译原理之二：预编译（Precompilation）</title><link>http://www.cnblogs.com/zohong/articles/1146879.html</link><dc:creator>二把刀</dc:creator><author>二把刀</author><pubDate>Thu, 10 Apr 2008 07:18:00 GMT</pubDate><guid>http://www.cnblogs.com/zohong/articles/1146879.html</guid><wfw:comment>http://www.cnblogs.com/zohong/comments/1146879.html</wfw:comment><comments>http://www.cnblogs.com/zohong/articles/1146879.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zohong/comments/commentRss/1146879.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zohong/services/trackbacks/1146879.html</trackback:ping><description><![CDATA[<p style="font-size: 10pt; font-family: Verdana;"><strong>1．为什么要进行预编译</strong></p>
<p style="font-size: 10pt; font-family: Verdana;">ASP.NET
2.0的编译方式大体可以分成两种：动态编译和预编译，要回答为什么要进行预编译，我们先要看看动态编译有什么不好的地方。我们回顾一下上一篇介绍的
ASP.NET进行动态编译的简单的流程：当来自Brower的一个基于aspx的Http request抵达Web server，IIS
handle这个request，通过分析注册在IIS中的Application Mapping，将Request
传给aspnet_isapi.dll ISAPI extension。ISAPI extension通过HttpRuntime进入Http
Runtime
Pipeline，HttpRuntime为每个Request创建一个单独的HttpContext对象，用于保存request的Context信
息。在Http Runtime Pipeline中，Http request会被注册的一系列的Http
module处理，比如OutputCache Module，Session Module，Authentication
Module，Authorization，ErrorHandler
Module等等。在Pipeline的终端，ASP.NET需要需要根据request创建对应的HttpHandler对象来处理该Request，
并生成结果Response到Client。对于一个基于Aspx的Http request，对应的Http
handler对象一般就是一个System.Web.UI.Page对象。</p>
<p style="font-size: 10pt; font-family: Verdana;">ASP.NET会先判断对应的Page
type是否存在于被Cache的Assembly中，如果存在，直接创建Page对象，否则ASP.NET会先对该Page的相关的Source
code (包括code behind，html等等)
进行编译，我们也说过这种编译是一Directory为单位的，也就是说，处于同一个Directory下的需要编译的文件会被编译成到同一个
Assembly中。编译生成的Assembly会被Cache，用于后续的Request。</p>
<p style="font-size: 10pt; font-family: Verdana;">正是因为对资源的首次访问会导致一次编译（这样
说不太准确，因为动态编译是以directory为单位进行的，应该对对某个Directory下的资源进行首次访问），这样会严重降低Web
Application的响应速度。所以我们为了避免这种情况，需要预先对web site进行编译，所以提高web
site的响应是进行预编译的最重要的原因。</p>
<p style="font-size: 10pt; font-family: Verdana;">同时动态编译就以为着Web
server上放置的是Source code，而且他们是可被修改的。而对于一个开发完毕的Web
Application，我们更希望以Binary Assembly的方式进行部署，这样Server上部署的都是Binary
Assembly，不怕被别人篡改而导致系统的崩溃，从知识产权来讲，也更利于保护商业秘密。这也是我们为什么要进行预编译的另一个原因。</p>
<p style="font-size: 10pt; font-family: Verdana;">下面我们就来讲讲如何进行预编译，以及与编译背
后的原理。同时在这里我需要特别提出的是，在上一部分讲的一些术语和原理，比如Preservation
file，FastObjectFactory，同样适用于预编译，重复的内容，在这里就不必再介绍了。同时我也将沿用上一部的Sample。如果想看看
相关的内容，请参阅<a id="_19ea6c024733_HomePageDays_DaysList_ctl00_DayItem_DayList_ctl00_TitleUrl" href="http://www.cnblogs.com/artech/archive/2007/05/21/753620.html">[原创]深入剖析ASP.NET的编译原理之一：动态编译（Dynamical Compilation）。</a></p>
<p style="font-size: 10pt; font-family: Verdana;"><strong>2．In Place Pre-compilation V.S. Pre-compilation for Deployment</strong></p>
<p style="font-size: 10pt; font-family: Verdana;">对于预编译，有可以分为In Place
Pre-compilation和Pre-compilation for Deployment，In Place
Pre-compilation很简单，实际上就是把整个Web
site编译到我们一个临时的目录下面，这个临时目录也就是我们在介绍动态编译提到的那个临时目录。而且这个编译的方式，包括生成的文件也和动态编译完全
一样，唯一不同就是编译的时间：预先编译，编译的范围：整个Web site。这种编译就是你常用的在VS的build。这种编译方式一般用于开发阶段。</p>
<p style="font-size: 10pt; font-family: Verdana;">为了部署为目的的编译是我们今天讨论的重点，下面我们就着重来讨论Pre-compilation for Deployment。</p>
<p style="font-size: 10pt; font-family: Verdana;">注：在ASP.NET的编译都是通过一个叫做
aspnet_compiler的工具执行的，该工具随ASP.NET
2.0一起发布，你完全可以利用此工具以命令行的方式的执行编译，并通过传递不同的命令行开关设置不同的编译选项。该工具被置于了VS中，使你可以利用
VS进行可视化的编译。</p>
<p style="font-size: 10pt; font-family: Verdana;"><strong>3．Non-updatable Pre-compilation V.S. Updatable Pre-compilation</strong></p>
<p style="font-size: 10pt; font-family: Verdana;">ASP.NET
2.0为我们提供了几种不同方式的预编译和部署。为了弄清楚这些预编译和部署方式，我们先来回顾一下ASP.NET
1.x下的编译方式。我们知道在ASP.NET 1.x时代对整个Web
site进行编译，实际上我们只会对所有C#和VB.NET等后台代码进行编译，并生成一个单一的Assembly。而Web
page的aspx是不会参与编译的。所以当我们访问一个Web page的时候，ASP.NET必须对aspx进行动态编译。</p>
<p style="font-size: 10pt; font-family: Verdana;">这一切之所以能够进行是因为Web page采用的是aspx + code behind的模式。</p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">%@&nbsp;Page&nbsp;</span><span style="color: #ff0000;">Language</span><span style="color: #0000ff;">="C#"</span><span style="color: #ff0000;">&nbsp;AutoEventWireup</span><span style="color: #0000ff;">="false"</span><span style="color: #ff0000;">&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Codebehind</span><span style="color: #0000ff;">="Default.aspx.cs"</span><span style="color: #ff0000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;Inherits</span><span style="color: #0000ff;">="Default"</span><span style="color: #ff0000;">&nbsp;%</span><span style="color: #0000ff;">&gt;</span></div>
<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" alt="" align="top" />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><img src="http://www.cnblogs.com/images/OutliningIndicators/None.gif" alt="" align="top" /><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">partial</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Default&nbsp;:&nbsp;System.Web.UI.Page<br />
<img id="Codehighlighter1_50_122_Open_Image" src="http://www.cnblogs.com/images/OutliningIndicators/ExpandedBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_50_122_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_50_122_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_50_122_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_50_122_Closed_Image" src="http://www.cnblogs.com/images/OutliningIndicators/ContractedBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_50_122_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_50_122_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_50_122_Open_Text').style.display='inline';" alt="" align="top" /></span><span id="Codehighlighter1_50_122_Closed_Text" style="border: 1px solid #808080; background-color: #ffffff; display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_50_122_Open_Text"><span style="color: #000000;">{<br />
<img src="http://www.cnblogs.com/images/OutliningIndicators/InBlock.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;Page_Load(</span><span style="color: #0000ff;">object</span><span style="color: #000000;">&nbsp;sender,&nbsp;EventArgs&nbsp;e)<br />
<img id="Codehighlighter1_113_120_Open_Image" src="http://www.cnblogs.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_113_120_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_113_120_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_113_120_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_113_120_Closed_Image" src="http://www.cnblogs.com/images/OutliningIndicators/ContractedSubBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_113_120_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_113_120_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_113_120_Open_Text').style.display='inline';" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_113_120_Closed_Text" style="border: 1px solid #808080; background-color: #ffffff; display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_113_120_Open_Text"><span style="color: #000000;">{<br />
<img src="http://www.cnblogs.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000;"><br />
<img src="http://www.cnblogs.com/images/OutliningIndicators/ExpandedBlockEnd.gif" alt="" align="top" />}</span></span></div>
<pre>从上面我们可以看到aspx和Code behind是一种继承的关系，aspx继承和它对应的Code Behind。ASP.NET可以把Code behind和aspx分开进行编译，把它们编译到不同的Assembly中。我们就是上面的Code为例，<br />
我们现在若对该Web site进行编译的话，Default.aspx.cs会被编译到一个Assembly中，假设这个Assembly为App_Web.dll. 我们把该Dll和aspx部署到Production Server上。如果我们现在访问defaut.aspx。ASP.NET<br />
会对aspx进行动态编译，生成的Assembly可以暂时成为App_Web_aspx.dll。对于Default.aspx，如果我们如C#代码来描述的话，应该像下面一样定义：</pre>
<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><img src="http://www.cnblogs.com/images/OutliningIndicators/None.gif" alt="" align="top" /><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;default_aspx:Default<br />
<img id="Codehighlighter1_34_37_Open_Image" src="http://www.cnblogs.com/images/OutliningIndicators/ExpandedBlockStart.gif" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_34_37_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_34_37_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_34_37_Closed_Text').style.display='inline';" alt="" align="top" /><img id="Codehighlighter1_34_37_Closed_Image" src="http://www.cnblogs.com/images/OutliningIndicators/ContractedBlock.gif" style="display: none;" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_34_37_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_34_37_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_34_37_Open_Text').style.display='inline';" alt="" align="top" /></span><span id="Codehighlighter1_34_37_Closed_Text" style="border: 1px solid #808080; background-color: #ffffff; display: none;"><img src="http://www.cnblogs.com/Images/dot.gif" alt="" /></span><span id="Codehighlighter1_34_37_Open_Text"><span style="color: #000000;">{<br />
<img src="http://www.cnblogs.com/images/OutliningIndicators/ExpandedBlockEnd.gif" alt="" align="top" />}</span></span></div>
<p style="font-size: 10pt; font-family: Verdana;">这种编译方式，我自己把它叫做对<span style="font-weight: bold;">asXx的动态编译</span>。
在ASP.NET2.0 中也沿用了这种编译方式。这种编译方式的主要特征是对Code
behind和所有的后台代码进行预编余，aspx（确切地说应该是asXx：asax，asmx，asax等）原样部署。由于这种方式的预编译，
asXx是可以修改的（当然这种修改是有一定限制的，因为code behind已经编译好了，所以这种修改只可能是和code
behind无关的修改），所以又叫做Updatable Pre-compilation。</p>
<p style="font-size: 10pt; font-family: Verdana;">除了Updatable
Pre-compilation之外，ASP.NET还提供另外一种高效的预编译方式，Non-updatable
Pre-compilation，之所以叫做不可修改的预编译，这是因为：这种编译方式把asXx、Code
behind、后台代码甚至是部分Resource都进行预编译，从而避免了运行时对asXx的动态编译，从而最大程度地提高了整个Web
site的响应。在部署的时候，我们除了把生成的Assembly进行部署之外，所有的通过编译生成的asXx也必须进行部署。
不过需要特别说明的是，此时的asXx文件仅仅是一个占位的文件而已，它里面不具有任何HTML。</p>
<p style="font-size: 10pt; font-family: Verdana;"><strong>4．Partial class</strong></p>
<p style="font-size: 10pt; font-family: Verdana;">在ASP.NET 1.x，由于采用的aspx&nbsp;+ code behind的机制，对于任何一个Web page或者其他ASP.NET 基于axXx的对象来说，都是由<span style="font-weight: bold;">两个文件、两个class组成</span>。两个文件是指axXx和code behind，两个class是指Code behind定义的继承自System.Web.UI.Page的class，和一个继承自它的由axXx生成的class。</p>
<p style="font-size: 10pt; font-family: Verdana;">对于使用过ASP.NET 1.x来说，一定会很熟悉这样一种情况：对于每个在aspx中通过HTML定义的Server Control，在Code behind中必须具有一个对应的<span style="font-weight: bold;">protected成员</span>，
否则你不能通过编程的方式访问这个Server control。以不同方式呈现的同一个Server
control通过ID关联起来，如果在Code behind中改了Server control的ID，Server
control的Server端的Event handler将会失去原有的作用。</p>
<p style="font-size: 10pt; font-family: Verdana;">但是在ASP.NET
2.0来说，这种情况发生了改变，在aspx中的Server control在Code
behind中却没有相应的成员变量，但是我们可以毫无障碍地访问到每个Server control。这使得我们的code
behind更加简洁，通过避免了Server control在aspx和code bebind中的不匹配的问题。这一切都得益于.NET
Framework 2.0提供的<span style="font-weight: bold;">partial class</span>的机制：<span style="font-weight: bold;">把同一个class分布于不同文件中进行定义</span>。有了这个概念，我们来看ASP.NET 2.0的code behind机制。</p>
<p style="font-size: 10pt; font-family: Verdana;">比如我们有这样的一个Page：</p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><img id="Codehighlighter1_2_92_Open_Image" onclick="this.style.display='none'; codehighlighter1_2_92_open_text.style.display=" none=""  ;="" codehighlighter1_2_92_closed_image.style.="" codehighlighter1_2_92_closed_text.style.="" display="'inline';" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" alt="" align="top" /><img id="Codehighlighter1_2_92_Closed_Image" style="display: none;" onclick="this.style.display='none'; codehighlighter1_2_92_closed_text.style.display=" none=""  ;="" codehighlighter1_2_92_open_image.style.="" codehighlighter1_2_92_open_text.style.="" display="'inline';" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" alt="" align="top" /><span style="color: #000000; background-color: #ffff00;">&lt;%</span><span id="Codehighlighter1_2_92_Open_Text"><span style="color: #000000; background-color: #f5f5f5;">@&nbsp;Page&nbsp;Language</span><span style="color: #000000; background-color: #f5f5f5;">=</span><span style="color: #000000; background-color: #f5f5f5;">"</span><span style="color: #000000; background-color: #f5f5f5;">C#</span><span style="color: #000000; background-color: #f5f5f5;">"</span><span style="color: #000000; background-color: #f5f5f5;">&nbsp;AutoEventWireup</span><span style="color: #000000; background-color: #f5f5f5;">=</span><span s