首先说明这里的代码复用指的是狭义的源代码的复用而不是广义的黑盒复用和白合复用所指的代码复用所以文中所说的代码复用都默认都是指前者所指的源代码的复用
我们知道在程序设计中复用代码并不是一件容易的事情其实每段代码的编写都是通过一定的思考的当然考虑的程度与其解决的问题的难度有关我们很忌讳在一个工程中重复使用相同的源代码如果出现这样的情况很多时候就是程序结构设计本身的不合理了可是对于一个developer或一个product team源代码的逻辑(主要是执行逻辑而不是业务逻辑)在不同项目或同一项目不同版本中很可能需要复用而这种复用很多时候又是很难抽象成广义的代码复用的于是我们不得不ctrl+c & ctrl+v这是一个好办法也确实能为我们节省很多的时间可是这样同时也会带来很多的问题如果被复用的代码是近期所写的我们一般对其很熟悉ctrl+v时心理也很有底可是对于编写了很久的代码我们在ctrl+v就不得不考虑一下代码是不时完全合适被复用了更多的时候我们还需要对复用代码做一些小的修改最简单的修改莫过于把变量名改来适合当前代码的上下文
如果有这样复用过代码的人可能会有一种感觉我总是不知道哪个源码文件里的代码snippet是我觉得解决这个逻辑最好的@_@因为每次ctrl+v后或多或少又会把代码做一些小的改动或是修补不足或是增加功能特别是修补了不足后如果能保留下来以做再次复用就好了可是很多时候这些越来越优秀的代码snippet却仍然分布在某个项目的某个文件中于是我们发现有些小工具可以用来帮助我们保存代码snippet比如前些天有人开发的类似CodeLib什么的
今天在用VSNET 的时候发现tools菜单里有一个Code Snippets Manager(或者用Ctrl+kCtrl+b呼出)打开看了一下第一感觉就是一个代码模版管理嘛看看了些预置的snippet居然都是些很简单的类似if语句结构for语句结构do语句结构while语句结构等觉得真是没有意思难道微软要我们用鼠标来编程吗?继续往后翻发现了几个比较复杂的snippets有的有一屏那么多的代码其实代码多少不是snippet的重要的问题了而是这些snippet在插入IDE后可以根据其在文件里的命令定义产生如下图所示的自动添补提示功能
在图中黄底黑字区域内编辑完后按Tab其下面的虚线框里的内容会同步的更新这样的功能为我们收集并复用源代码提供了很便利的支持这个snippet是以xml格式保存的只是whidbey beta里面还没没有提供snippet文件的可视化编辑器不过xml本身在VSNET里也不难写上图示例的代码文件如下
<CodeSnippet Format=>
<Header>
<Title>named iterator / indexer pair</Title>
<Shortcut>iterindex</Shortcut>
<Description>Implement a named iterator / indexer pair using a nested class</Description>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<Default>ElementType</Default>
<ToolTip>Type to return from iterator / indexer</ToolTip>
</Literal>
<Literal>
<ID>name</ID>
<Default>MyView</Default>
<ToolTip>Name of the iterator/indexer pair</ToolTip>
</Literal>
<Literal Editable=false>
<ID>outer</ID>
<Default>MyOuterClass</Default>
<Function>ClassName()</Function>
</Literal>
<Literal Editable=false>
<ID>SystemCollectionsGenericIEnumeratorG</ID>
<! Function>ShortName(SystemIEnumerator)</Function >
<Default>SystemCollectionsGenericIEnumerator</Default>
</Literal>
<Literal Editable=false>
<ID>SystemNotImplementedException</ID>
<! Function>ShortName(SystemNotImplementedException)</Function >
<Default>SystemNotImplementedException</Default>
</Literal>
</Declarations>
<Code Language=csharp Format=CData><![CDATA[public $name$Impl $name$
{
get
{
return new $name$Impl(this);
}
}
public class $name$Impl
{
readonly $outer$ _outer;
internal $name$Impl($outer$ mc)
{
this_outer = mc;
}
// A Length property isnt required but its often useful
public int Length { get { return ; } }
public $type$ this[int index]
{
get
{
//
// TODO: implement indexer here
//
// you have full access to $outer$ privates
//
$end$throw new SystemNotImplementedException();
return default($type$);
}
}
public $SystemCollectionsGenericIEnumeratorG$<$type$> GetEnumerator()
{
// TODO: provide an appropriate implementation here
for (int i = ; i < thisLength; i++)
{
yield return this[i];
}
}
}]]>
</Code>
</Snippet>
</CodeSnippet>
有了这个snippet的管理支持和方便的使用方法后基本就解决了我前面提到源代码复用里面版本控制和变量名修改的问题
其实这个snippet的使用还有一个积极的意义我们知道编写相同的逻辑过程是枯燥的我们都喜欢编写新的逻辑过程即使新的逻辑更难更复杂反而更有挑战但是我们又不能避开很多程序逻辑的复用在我们以一种类似厌恶的情绪重复着那些程序逻辑时保证代码的正确性真是一场噩梦