﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-玄铁剑-文章分类-Code generate</title><link>http://www.cnitblog.com/MartinYao/category/4796.html</link><description>成功的途径：抄，创造，研究，发明...</description><language>zh-cn</language><lastBuildDate>Mon, 26 Sep 2011 12:56:18 GMT</lastBuildDate><pubDate>Mon, 26 Sep 2011 12:56:18 GMT</pubDate><ttl>60</ttl><item><title>Code Generator using CodeSmith Api</title><link>http://www.cnitblog.com/MartinYao/articles/22639.html</link><dc:creator>玄铁剑</dc:creator><author>玄铁剑</author><pubDate>Sat, 03 Feb 2007 15:04:00 GMT</pubDate><guid>http://www.cnitblog.com/MartinYao/articles/22639.html</guid><wfw:comment>http://www.cnitblog.com/MartinYao/comments/22639.html</wfw:comment><comments>http://www.cnitblog.com/MartinYao/articles/22639.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/MartinYao/comments/commentRss/22639.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/MartinYao/services/trackbacks/22639.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr valign="top">
								<td width="100%">
										<table width="100%">
												<tbody>
														<tr valign="top">
																<td class="SmallText" nowrap="">
																</td>
																<td nowrap="" align="right">
																		<a name="__top">
																		</a>
																		<table>
																				<tbody>
																						<tr>
																								<td class="smallText" align="right">9 votes for this article.</td>
																								<td>
																										<table cellspacing="0" cellpadding="0" border="2">
																												<tbody>
																														<tr>
																																<td>
																																		<img height="5" src="http://www.codeproject.com/script/images/red.gif" width="20" border="0" />
																																</td>
																																<td>
																																		<img height="5" src="http://www.codeproject.com/script/images/red.gif" width="20" border="0" />
																																</td>
																																<td>
																																		<img height="5" src="http://www.codeproject.com/script/images/red.gif" width="11" border="0" />
																																		<img height="5" src="http://www.codeproject.com/script/images/white.gif" width="9" border="0" />
																																</td>
																																<td>
																																		<img height="5" src="http://www.codeproject.com/script/images/white.gif" width="20" border="0" />
																																</td>
																																<td>
																																		<img height="5" src="http://www.codeproject.com/script/images/white.gif" width="20" border="0" />
																																</td>
																														</tr>
																												</tbody>
																										</table>
																								</td>
																						</tr>
																						<tr>
																								<td class="smallText" align="right" colspan="2">
																										<a title="Calculated as rating x Log10(# votes)" href="http://www.codeproject.com/script/articles/top_articles.asp?st=2">Popularity: 2.45</a>. Rating: <b>2.57</b> out of 5.</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
						<tr>
								<td class="ArticlePane">
										<span id="intelliTXT">
												<div id="contentdiv">
														<!-- Article Starts -->
														<ul class="download">
																<li>
																		<a href="http://www.codeproject.com/csharp/Code_Generator/Final_Templates.zip">Download source files - 36 Kb</a>
																</li>
																<li>
																		<a href="http://www.codeproject.com/csharp/Code_Generator/CodeGenerator.zip">Download demo project - 3661 Kb</a>
																</li>
														</ul>
														<p>
																<img height="462" alt="Sample Image - Code_Generator.jpg" src="http://www.codeproject.com/csharp/Code_Generator/codegen.jpg" width="600" />
														</p>
														<h2>Introduction</h2>
														<p>
														</p>
														<p nd="1">Before I start to explain what my code generator is and how it works, I want to let you people what thing have hit me to write this article and my code generator.</p>
														<p nd="2">Well as all programmer knows that writing code for DAL and BL is time consuming and we write same lines of code for each project excepts some custom changing, so I was wondering by we take such burden every time there should some other fast, easiest , efficient way, so I started to explorer it and started working on that, as I progress I find CodeSmith (<a href="http://www.codesmithtools.com/">www.codesmithtools.com</a>) as a useful tool to achieve that.</p>
														<p nd="3">CodeSmith enables software developers to efficiently:</p>
														<ul>
																<li nd="4">Reduce repetitive coding 
</li>
																<li nd="5">Generate your code in less time with fewer bugs 
</li>
																<li nd="6">Produce consistent code that adheres to your standards 
</li>
																<li nd="7">Create your own custom templates for any language </li>
														</ul>
														<p nd="8">So I started to learn the codesmith, and luckly due to its easy structure I grasp its concept , working quickly.</p>
														<p nd="9">Now I should explain the working of my software. First of I started to work on writing templates for myself. I stated building my own frame work, As I am beginner so started to understand the .netTiers Application Framework (<a href="http://www.nettiers.com/">http://www.nettiers.com</a>). After under standing this framework I started to build my framework and get some help from the .netTiers Application Framework. </p>
														<p nd="10">My framework consist of the following classes</p>
														<ul>
																<li nd="11">Entity Class 
</li>
																<li nd="12">Entity Base Class 
</li>
																<li nd="13">EntityController Class 
</li>
																<li nd="14">EntityController Base Cclass 
</li>
																<li nd="15">DataProvider Class 
</li>
																<li nd="16">DataProvider Base Class 
</li>
																<li nd="17">GenericList Class 
</li>
																<li nd="18">CBO Class </li>
														</ul>
														<p>
																<b>Entity Class:</b>
														</p>
														<p nd="19">This class is inherited from the base class Entity Base Class, the entity class contain no function but you can override the virtual function in the base class, and if you want some custom function then you can write your own function in the entity class no in the base class.</p>
														<p>
																<b>Entity Base Class;</b>
														</p>
														<p nd="20">This class have the properties , methods to that should be required for the database table. Its an abstract class. This class have the following functions other then the constructor </p>
														<ul type="disc">
																<li nd="21">Equals 
</li>
																<li nd="22">GetHashCode </li>
														</ul>
														<p>
																<b>EntityController Class:</b>
														</p>
														<p nd="23">This class is inherited from the base class EntityController Base Class, this class can also override the virtual functions from the base class.</p>
														<p>
																<b>EntityController Base Class:</b>
														</p>
														<p nd="24">This class have the basic methods as follows</p>
														<ul type="disc">
																<li nd="25">Add(with four overloaded methods 
</li>
																<li nd="26">Update(with four overloaded methods) 
</li>
																<li nd="27">Delete(with four overloaded methods) 
</li>
																<li nd="28">GetPagedData(for getting data in the form of page) 
</li>
																<li nd="29">DeleteAll 
</li>
																<li nd="30">Get 
</li>
																<li nd="31">GetAll 
</li>
																<li nd="32">GetCustomView(to get the custom data base table columns 
</li>
																<li nd="33">GetByPk 
</li>
																<li nd="34">CountAll 
</li>
																<li nd="35">GetByFk </li>
														</ul>
														<p nd="36">This class call the function of the DataProvider class to interact with the database.</p>
														<p>
																<b>DataProvider Class:</b>
														</p>
														<p nd="37">This class is inherited from the base class DataProvider Base Class, this class can also override the virtual functions from the base class.</p>
														<p>
																<b>DataProvider Base Class:</b>
														</p>
														<p nd="38">This class actually interact with the database. For this purpose I uses the Microsoft Enterprise Library 2006. which provide efficient data access libraries. You can download the enterprise library from the Microsoft site (<a href="http://www.microsoft.com/">www.microsoft.com</a>).</p>
														<p>
																<b>GenericList Class:</b>
														</p>
														<p nd="39">In my framework for getting data in bundle I uses generic list instead of the datasets, for this I write the generic class.</p>
														<p>
																<b>CBO Class:</b>
														</p>
														<p nd="40">For converting the object to the required class or entity object I use this class.</p>
														<p>
																<b>CodeGenerator:</b>
														</p>
														<p>
																<img height="465" src="http://www.codeproject.com/csharp/Code_Generator/codegen2.JPG" width="600" border="0" />
														</p>
														<p nd="41">I wrote CodeSmith templates for above mentions class, other then these to class I wrote an other template which was use to generate the store procedure which will be use by the methods in the DataProvider Base Class. </p>
														<p nd="42">Now come to point why I write the application for compiling the CodeSmith templates that I have written, the problem was that to generate the code for the some database we have to compile each template for each table. So it take some time and also some hectic, so I develop the application to perform this work, I generate the code using all these templates by just info about the database. I develop this tool which uses CodeSmith API to compile the templates. Please install the CodeSmith 3.2 on your system to generate the code </p>
														<p>
																<img height="462" src="http://www.codeproject.com/csharp/Code_Generator/codegen3.JPG" width="600" border="0" />
														</p>
														<p nd="43">There was another class for the CodeSmith templates which was code behind class SqlScript.cs; I adopted this class from the .netTiers Application Framework (<a href="http://www.nettiers.com/">http://www.nettiers.com</a>). And have some custom function to be used in my framework.</p>
														<p nd="44">Please let me know about your suggestions and comments thanks, and I am working on to version capability like dot net 2003 and dot net 2005. And also to compile the other templates also not specific related to my frame work</p>
														<p nd="45">Name: Muhammad Shafqat Masood</p>
														<p nd="46">Software Engineer (Nextbridge)</p>
														<p nd="47">Contact: Napster_ghb@yahoo.com</p>
												</div>
										</span>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cnitblog.com/MartinYao/aggbug/22639.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/MartinYao/" target="_blank">玄铁剑</a> 2007-02-03 23:04 <a href="http://www.cnitblog.com/MartinYao/articles/22639.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Plugging a CodeSmith-style Template Engine Directly into the VS.NET IDE</title><link>http://www.cnitblog.com/MartinYao/articles/22638.html</link><dc:creator>玄铁剑</dc:creator><author>玄铁剑</author><pubDate>Sat, 03 Feb 2007 14:40:00 GMT</pubDate><guid>http://www.cnitblog.com/MartinYao/articles/22638.html</guid><wfw:comment>http://www.cnitblog.com/MartinYao/comments/22638.html</wfw:comment><comments>http://www.cnitblog.com/MartinYao/articles/22638.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/MartinYao/comments/commentRss/22638.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/MartinYao/services/trackbacks/22638.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr valign="top">
								<td width="100%">
										<table width="100%">
												<tbody>
														<tr valign="top">
																<td class="SmallText" nowrap="">
																</td>
																<td nowrap="" align="right">
																		<a name="__top">
																		</a>
																		<table>
																				<tbody>
																						<tr>
																								<td class="smallText" align="right">10 votes for this article.</td>
																								<td>
																										<table cellspacing="0" cellpadding="0" border="2">
																												<tbody>
																														<tr>
																																<td>
																																		<img height="5" src="http://www.codeproject.com/script/images/red.gif" width="20" border="0" />
																																</td>
																																<td>
																																		<img height="5" src="http://www.codeproject.com/script/images/red.gif" width="20" border="0" />
																																</td>
																																<td>
																																		<img height="5" src="http://www.codeproject.com/script/images/red.gif" width="20" border="0" />
																																</td>
																																<td>
																																		<img height="5" src="http://www.codeproject.com/script/images/red.gif" width="20" border="0" />
																																</td>
																																<td>
																																		<img height="5" src="http://www.codeproject.com/script/images/red.gif" width="3" border="0" />
																																		<img height="5" src="http://www.codeproject.com/script/images/white.gif" width="17" border="0" />
																																</td>
																														</tr>
																												</tbody>
																										</table>
																								</td>
																						</tr>
																						<tr>
																								<td class="smallText" align="right" colspan="2">
																										<a title="Calculated as rating x Log10(# votes)" href="http://www.codeproject.com/script/articles/top_articles.asp?st=2">Popularity: 4.17</a>. Rating: <b>4.17</b> out of 5.</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
						<tr>
								<td class="ArticlePane">
										<span id="intelliTXT">
												<div id="contentdiv">
														<!-- Article Starts -->
														<ul class="download">
																<li>
																		<a href="http://www.codeproject.com/dotnet/TaHoGen2/ManagedAddIns-1_0_33.zip">Download ManagedAddIns Library v1.033 - 1.0 MB</a>
																</li>
																<li>
																		<a href="http://www.codeproject.com/dotnet/TaHoGen2/TaHoGenCoreInstaller.zip">Download the updated version of TaHoGen, v1.03 - 511 Kb</a>
																</li>
																<li>
																		<a href="http://www.codeproject.com/dotnet/TaHoGen2/TaHoGenVSAddIn_Src.zip">Download the add-in source code - 33.1 Kb</a>
																</li>
																<li>
																		<a href="http://www.codeproject.com/dotnet/TaHoGen2/TaHoGenVSAddIn_Installer.zip">Download the add-in installer - 1.04 MB</a>
																</li>
														</ul>
														<p>
																<a title="Click to enlarge" href="http://www.codeproject.com/dotnet/TaHoGen2/AddinShot2_big.JPG" target="_blank">
																		<img height="450" src="http://www.codeproject.com/dotnet/TaHoGen2/AddinShot2.JPG" width="600" border="0" />
																</a>
														</p>
														<h2>Introduction</h2>
														<p nd="1">In this article of this series, I’m going to show you a simple VS.NET Add-In client I wrote for the TaHoGen template engine. (If you’re not familiar with TaHoGen, you can think of it as an Open Source implementation of a CodeSmith-compatible code generation engine.) Furthermore, we’re going to take it a step further by allowing the user to output his/her templates directly into the VS.NET Code Editor windows.</p>
														<h2>Background</h2>
														<p nd="2">One of the things that I’ve always wanted to do is to be able to run a CodeSmith template and send the output of that template directly to the code window. Unfortunately, the current version of CodeSmith (version 3.0 at the time of this writing) doesn’t support that out of the box. Secondly, its source code is proprietary, leaving Open Source tool developers like me with little or no options to work with. It’s either you buy a license to use it in your products, or you can’t use it at all (except from within CodeSmith itself).</p>
														<p nd="3">For me, both options were unacceptable, and that was why the TaHoGen engine was born. The difference between TaHoGen and CodeSmith in this regard is simple: as long as you use TaHoGen in another project licensed under the terms of the GNU Public License, I will never, ever, charge you a cent for it. If you decide to include it in a commercial product, however, then, that’s a different story…</p>
														<p nd="4">So, now that we as a developer community have our own Open Source CodeSmith-style compatible code generation engine (yeah, I know, that’s quite a mouthful), it’s time to make something useful out of it—let’s get started!</p>
														<h2>What you’re going to need before we get started</h2>
														<p nd="5">In addition to the TaHoGen Core Libraries from the previous article, you’re going to need:</p>
														<ul>
																<li nd="6">
																		<b>Phil Wright’s MagicLibrary</b>. You can get it from <a href="http://www.dotnetmagic.com/" target="_blank">here</a>. 
</li>
																<li nd="7">
																		<b>MutantDesign’s Managed AddIns Library &amp; AddIn Manager</b>. Normally, you can find these libraries included as part of the TestDriven.NET library. (For your convenience, I’ve included a copy of the MSI installer that I used as a part of this add-in, in the section above.) </li>
														</ul>
														<h2>Using the client</h2>
														<p nd="8">Once you’ve installed the two libraries that I mentioned earlier (namely the ManagedAddIns library) and installed the add-in itself, you should get an option in your Tools menu in VS.NET that looks like this:</p>
														<p>
																<img height="262" src="http://www.codeproject.com/dotnet/TaHoGen2/toolmenu.jpg" width="218" />
														</p>
														<p nd="9">After you click on that option in the menu, you should see a dialog similar to the following appear:</p>
														<p>
																<img height="366" src="http://www.codeproject.com/dotnet/TaHoGen2/toolbox2.jpg" width="550" />
														</p>
														<p nd="10">Once you choose the File-&gt;Open option on the menu, a standard OpenFileDialog will ask you where you installed the add-in. Once you’ve selected where the file (<i>TaHoGen.VSAddIn.exe</i>) is located, the only thing you have to do is right click on the <i>TaHoGen.VSAddIn</i> list item and click on <b>Connect</b>. You should then see something like this:</p>
														<p>
																<img height="261" src="http://www.codeproject.com/dotnet/TaHoGen2/templatetab.jpg" width="450" />
														</p>
														<p nd="11">This should be pretty familiar to those of you used to using the CodeSmith Explorer interface. (For now, don’t worry if you don’t see anything listed on the tree view just yet—we’ll get to that in a bit.) Double-clicking on a single template in the tree view will compile that template, and the add-in will automatically show you the properties for that template:</p>
														<p>
																<img height="382" src="http://www.codeproject.com/dotnet/TaHoGen2/propertytab.jpg" width="390" />
														</p>
														<p nd="12">In this case, I double-clicked on the <i>CSHashtable.cst</i> template, and these were the properties that automatically came up. If you click on the <i>Generate</i> button, what will happen is that the add-in will run the template and send its output to the active code editor window in the VS.NET IDE. So, for example, if I wanted to generate a new strongly-typed collection (or hashtable, in this case), all I have to do is choose File-&gt;New-&gt;File…-&gt;New Text Document from the VS.NET IDE menu and click on the <i>Generate</i> button to dump the output of the template into the new file, and save and add that file as part of my project. It can’t get any simpler than that.</p>
														<p nd="13">The rest of the options on this tab are fairly self-explanatory, so let’s move on to the next section.</p>
														<h3>Viewing the Output</h3>
														<p nd="14">There might be times where you need to see the diagnostic output of the code generation engine. For example, if a template fails to compile, we need to know exactly why it failed so we can go about fixing the compilation error(s). With that in mind, the add-in sends all of its messages to the output window to make templates easier to debug:</p>
														<p>
																<img height="332" src="http://www.codeproject.com/dotnet/TaHoGen2/outputwindow.jpg" width="578" />
														</p>
														<p nd="15">The add-in adds two new output window panes to the output window:</p>
														<ul>
																<li nd="16">
																		<b>TaHoGen Build Output</b>. This window will report any compile errors if they occur, in addition to any other error messages TaHoGen will display if something goes wrong. 
</li>
																<li nd="17">
																		<b>TaHoGen Generated Template Source</b>.<b></b>This window shows you what the code generator you created would have looked like if you were to write it by hand. (This is useful for debugging code generators with additional code written in some script blocks in the template markup.) </li>
														</ul>
														<h3>Editing Template Files from within Visual Studio .NET</h3>
														<p nd="18">The add-in makes it easy to edit your template files without having to leave the confines of the VS.NET IDE. All you have to do is right click on any template file, choose the <i>Edit</i> option from the context menu, and you can edit the template file from within the IDE, as seen from this image:</p>
														<p>
																<img height="210" src="http://www.codeproject.com/dotnet/TaHoGen2/templatetab3.jpg" width="218" />
														</p>
														<p nd="19">In addition, if you make any changes to your template files within the IDE and need to rebuild, all you have to do is right click on the selected template, and choose the <i>Build</i> option.</p>
														<h3>Adding and Removing Template Directories</h3>
														<p nd="20">The <i>Options</i> tab lets you choose the directories the add-in should use to recursively search for (both TaHoGen and CodeSmith) template files. For example, here’s how it would look if you decided to add a few sample templates from the CodeSmith installation folder:</p>
														<p>
																<img height="379" src="http://www.codeproject.com/dotnet/TaHoGen2/optionstab.jpg" width="387" />
														</p>
														<p nd="21">Once you select a directory, the add-in will update the treeview in the <i>Templates</i> tab with the new list of templates, and you’ll be able to use them just as you would be able to use any other template.</p>
														<h2>Using the code</h2>
														<p nd="22">Despite its functionality, the add-in itself is no more than a thousand lines of (mostly) user interface code. I won’t bore you with all the details since most of it is boilerplate code; instead, we’ll just pick up where we left off in the previous article, and I’ll show you a few notable portions of the code so you can see what’s going on behind the scenes.</p>
														<h3>Compiling the Template</h3>
														<p nd="23">As I mentioned in the previous article, you can compile a single template using the following lines of code:</p>
														<pre lang="cs" nd="25">
																<span class="cs-keyword" nd="24">string</span> sourceText = “…”;
CompilerCallback callback = <span class="cs-keyword" nd="26">new</span> CompilerCallback();
…
Assembly templateAssembly = TemplateCompiler.Compile(sourceText, 
                                           <span class="cpp-string" nd="27">""</span>, <span class="cs-keyword" nd="28">false</span>, callback); 
…</pre>
														<p nd="29">In this particular case, the add-in is reading the contents of a template file and sending its contents to the compiler. The <code nd="30">TemplateCompiler</code> class has the following signature:</p>
														<pre lang="cs" nd="34">
																<span class="cs-comment" nd="31">// Methods for compiling a single template</span>
																<span class="cs-keyword" nd="32">public</span>
																<span class="cs-keyword" nd="33">static</span> Assembly Compile(<span class="cs-keyword" nd="35">string</span> text)
<span class="cs-keyword" nd="36">public</span><span class="cs-keyword" nd="37">static</span> Assembly Compile(<span class="cs-keyword" nd="38">string</span> text, <span class="cs-keyword" nd="39">bool</span> addDebugSymbols)
<span class="cs-keyword" nd="40">public</span><span class="cs-keyword" nd="41">static</span> Assembly Compile(<span class="cs-keyword" nd="42">string</span> text, <span class="cs-keyword" nd="43">string</span> outputFileName, 
                               <span class="cs-keyword" nd="44">bool</span> addDebugSymbols)
<span class="cs-keyword" nd="45">public</span><span class="cs-keyword" nd="46">static</span> Assembly Compile(<span class="cs-keyword" nd="47">string</span> text, <span class="cs-keyword" nd="48">string</span> outputFileName, 
                               <span class="cs-keyword" nd="49">bool</span> addDebugSymbols, 
                               ICompilerCallback compilerCallback)

<span class="cs-comment" nd="50">// Methods for compiling multiple templates</span><span class="cs-comment" nd="51">// into one assembly (not shown)</span>
…</pre>
														<p nd="52">The first three parameters are self-explanatory. The fourth parameter, however, needs a little more explanation. The <code nd="53">ICompilerCallback</code> interface is useful if you need to show the results of a compilation to the user. It is defined as follows:</p>
														<pre lang="cs" nd="56">
																<span class="cs-keyword" nd="54">public</span>
																<span class="cs-keyword" nd="55">interface</span> ICompilerCallback
{
  <span class="cs-keyword" nd="57">void</span> BeginCompile(CompilerArgs args);
  <span class="cs-keyword" nd="58">void</span> EndCompile(CompilerArgs args);
}</pre>
														<p nd="59">The <code nd="60">CompilerArgs</code> class, in turn, is defined as:</p>
														<pre lang="cs" nd="63">
																<span class="cs-keyword" nd="61">public</span>
																<span class="cs-keyword" nd="62">class</span> CompilerArgs
{
  <span class="cs-keyword" nd="64">private</span><span class="cs-keyword" nd="65">string</span> _source;
  <span class="cs-keyword" nd="66">private</span> CompilerErrorCollection _errors = <span class="cs-keyword" nd="67">new</span> CompilerErrorCollection();
  <span class="cs-keyword" nd="68">public</span> CompilerArgs(<span class="cs-keyword" nd="69">string</span> source, CompilerErrorCollection errors) 
  {
      _source = source;
      <span class="cs-keyword" nd="70">if</span> (errors != <span class="cs-keyword" nd="71">null</span>)
          _errors.AddRange(errors);
  }
  <span class="cs-keyword" nd="72">public</span><span class="cs-keyword" nd="73">string</span> CompiledCode
  {
    <span class="cs-keyword" nd="74">get</span> { <span class="cs-keyword" nd="75">return</span> _source; }
  }
  <span class="cs-keyword" nd="76">public</span> CompilerErrorCollection Errors
  {
       <span class="cs-keyword" nd="77">get</span> { <span class="cs-keyword" nd="78">return</span> _errors; }
  }
}</pre>
														<h3>Getting the results from the compiler</h3>
														<p nd="79">In order to get the results from the compiler, I had to define my own class implementation of <code nd="80">ICompilerCallback</code>:</p>
														<div class="precollapse" id="premain4" style="WIDTH: 100%">
																<img id="preimg4" style="CURSOR: hand" height="9" src="http://www.codeproject.com/images/minus.gif" width="9" preid="4" />
																<span id="precollapse4" style="MARGIN-BOTTOM: 0px; CURSOR: hand" nd="81" preid="4"> Collapse</span>
														</div>
														<pre lang="cs" id="pre4" style="MARGIN-TOP: 0px" nd="83">
																<span class="cs-keyword" nd="82">using</span> System;
<span class="cs-keyword" nd="84">using</span> System.CodeDom.Compiler;
<span class="cs-keyword" nd="85">using</span> System.Reflection;
<span class="cs-keyword" nd="86">using</span> TaHoGen;

<span class="cs-keyword" nd="87">namespace</span> TaHoGen.VSAddIn
{
    <span class="cs-keyword" nd="88">public</span><span class="cs-keyword" nd="89">class</span> CompilerCallback : ICompilerCallback
    {
        <span class="cs-keyword" nd="90">private</span><span class="cs-keyword" nd="91">string</span> _templateCode;
<span class="cs-preprocessor" nd="92">        #region ICompilerCallback Members</span><span class="cs-keyword" nd="93">public</span><span class="cs-keyword" nd="94">void</span> BeginCompile(CompilerArgs args)
        {
            Console.WriteLine(<span class="cpp-string" nd="95">"----------------- Compile Started ----------------"</span>);
            Console.WriteLine();
        }

        <span class="cs-keyword" nd="96">public</span><span class="cs-keyword" nd="97">void</span> EndCompile(CompilerArgs args)
        {
            <span class="cs-comment" nd="98">// Save the compiled code so that</span><span class="cs-comment" nd="99">// we can show it to the user later</span>
            _templateCode = args.CompiledCode;

            <span class="cs-keyword" nd="100">foreach</span>(CompilerError error <span class="cs-keyword" nd="101">in</span> args.Errors)
            {
                <span class="cs-keyword" nd="102">string</span> msg = <span class="cs-keyword" nd="103">string</span>.Format(<span class="cpp-string" nd="104">"{0}({1}, {2}): error {3}: {4}"</span>, 
                                           error.FileName, 
                                           error.Line, 
                                           error.Column, 
                                           error.ErrorNumber, 
                                           error.ErrorText);
                Console.WriteLine(msg);
            }
            Console.WriteLine(<span class="cpp-string" nd="105">"Build Complete - {0} Errors, 0 Warnings"</span>, 
                                                     args.Errors.Count);
            Console.WriteLine();
            Console.WriteLine(<span class="cpp-string" nd="106">"---------------------- Done ----------------------"</span>);
            Console.WriteLine();

            <span class="cs-keyword" nd="107">string</span> text = args.Errors.Count &gt; <span class="cs-literal" nd="108">0</span> ? <span class="cpp-string" nd="109">"Build Failed"</span> : 
                                                   <span class="cpp-string" nd="110">"Build Succeeded"</span>;
            Console.WriteLine(text);
        }

<span class="cs-preprocessor" nd="111">        #endregion</span><span class="cs-keyword" nd="112">public</span><span class="cs-keyword" nd="113">string</span> GeneratedTemplateCode
        {
        <span class="cs-keyword" nd="114">get</span> { <span class="cs-keyword" nd="115">return</span> _templateCode; }
        }
    }
}</pre>
														<p nd="116">As you can see, the implementation of the class is very straightforward. The <code nd="117">CompilerCallback</code> class marks the beginning and end of the compilation process, reports any compilation errors if they occur, and saves the generated template code so that we can display it to the end user once it’s done compiling. The only thing that seems to be out of the ordinary here is the calls to <code nd="118">Console.WriteLine()</code> — how do you get its output to show up on the output window in VS.NET?</p>
														<h3>Redirecting the Console Output</h3>
														<p nd="119">It turns out that the <code nd="120">Console</code> class has a single static method named <code nd="121">SetOut()</code> that allows us to redirect its output to any object derived from <code nd="122">System.IO.TextWriter</code>. In this case, we’re redirecting the console output to a <code nd="123">StringWriter</code> class so that we can dump its contents to an output window once the template finishes compiling:</p>
														<pre lang="cs" nd="124">StreamReader reader = <span class="cs-keyword" nd="125">new</span> StreamReader(fileName);
<span class="cs-keyword" nd="126">string</span> sourceText = reader.ReadToEnd();

<span class="cs-comment" nd="127">// The StringWriter will store the output of the compiler</span>
StringWriter buildOutput = <span class="cs-keyword" nd="128">new</span> StringWriter();

Console.SetOut(buildOutput);

<span class="cs-comment" nd="129">// Compile the template</span>
CompilerCallback callback = <span class="cs-keyword" nd="130">new</span> CompilerCallback();
Assembly templateAssembly = TemplateCompiler.Compile(sourceText, 
                                           <span class="cpp-string" nd="131">""</span>, <span class="cs-keyword" nd="132">false</span>, callback);

…

<span class="cs-comment" nd="133">// Send the results to the output window</span>
_buildOutputPane.OutputString(buildOutput.ToString());</pre>
														<h3>Showing the Compiled Template Code</h3>
														<p nd="134">Next, we need to show the generated template code:</p>
														<pre lang="cs" nd="135">…
<span class="cs-comment" nd="136">// Show the compiled code</span>
_generatedSourcePane.OutputString(callback.GeneratedTemplateCode);
…</pre>
														<p nd="137">…and that’s all there is to sending text to an output window in VS.NET.</p>
														<h3>Adding Extra Output Panes</h3>
														<p nd="138">If you’re wondering how I added those extra output window panes, here’s the code I used to do it:</p>
														<div class="precollapse" id="premain7" style="WIDTH: 100%">
																<img id="preimg7" style="CURSOR: hand" height="9" src="http://www.codeproject.com/images/minus.gif" width="9" preid="7" />
																<span id="precollapse7" style="MARGIN-BOTTOM: 0px; CURSOR: hand" nd="139" preid="7"> Collapse</span>
														</div>
														<pre lang="cs" id="pre7" style="MARGIN-TOP: 0px" nd="147">
																<span class="cs-comment" nd="140">/// &lt;summary&gt;</span>
																<span class="cs-comment" nd="141">/// Creates a special pane in the output window of the VS.NET IDE.</span>
																<span class="cs-comment" nd="142">/// &lt;/summary&gt;</span>
																<span class="cs-comment" nd="143">/// &lt;param name="paneName"&gt;The name of the pane to create.&lt;/param&gt;</span>
																<span class="cs-comment" nd="144">/// &lt;returns&gt;An OutputWindowPane.&lt;/returns&gt;</span>
																<span class="cs-keyword" nd="145">private</span>
																<span class="cs-keyword" nd="146">static</span> OutputWindowPane CreatePane(<span class="cs-keyword" nd="148">string</span> paneName)
{
    <span class="cs-comment" nd="149">// We’re interested only in output windows</span>
    Window window = 
      ManagedAddIns.DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
    OutputWindow outputWindow = window.Object <span class="cs-keyword" nd="150">as</span> OutputWindow;
    OutputWindowPane outputPane = <span class="cs-keyword" nd="151">null</span>;


    outputPane = <span class="cs-keyword" nd="152">null</span>;
    OutputWindowPanes panes = outputWindow.OutputWindowPanes;

    <span class="cs-comment" nd="153">// Reuse the existing pane (if it exists)</span><span class="cs-keyword" nd="154">for</span>(<span class="cs-keyword" nd="155">int</span> i = <span class="cs-literal" nd="156">1</span>; i &lt;= panes.Count; i++)
    {
        outputPane = panes.Item(i);
        <span class="cs-keyword" nd="157">if</span> (outputPane.Name == paneName)
            <span class="cs-keyword" nd="158">return</span> outputPane;
    }
    <span class="cs-comment">// Otherwise, we’re going to create a new pane</span>
    OutputWindowPane newPane = outputWindow.OutputWindowPanes.Add(paneName);

    <span class="cs-keyword">return</span> newPane;
}</pre>
														<h3>Attaching the Template to the PropertyGrid</h3>
														<p>Wiring a template object to a <code>PropertyGrid</code> is equally just as simple. Once the template has been instantiated, the only thing left to do is to attach it to the property grid so that the user can set the template properties:</p>
														<pre lang="cs">…
<span class="cs-comment">// Instantiate the template type</span><span class="cs-keyword">object</span> template = Activator.CreateInstance(templateType);

_template = template <span class="cs-keyword">as</span> ITextGenerator;

<span class="cs-comment">// Once we're done compiling, we</span><span class="cs-comment">// need to give the user a chance to</span><span class="cs-comment">// set the properties for the template.</span>

propertyGrid1.SelectedObject = _template;
…</pre>
														<h3>Sending the Template Output to the Active Code Editor Window</h3>
														<p>Lastly, the add-in sends the output of the template to the current code window using the following code:</p>
														<pre lang="cs">
																<span class="cs-comment">// Output the generated code at the current selection</span>
TextSelection selection = 
  ManagedAddIns.DTE.ActiveDocument.Selection <span class="cs-keyword">as</span> TextSelection;
Debug.Assert(selection != <span class="cs-keyword">null</span>);

<span class="cs-comment">// Save the output of the template</span><span class="cs-comment">// when it runs</span>
StringTarget target = <span class="cs-keyword">new</span> StringTarget();
target.Attach(_template);


<span class="cs-comment">// Run the template itself</span>
target.Write();


<span class="cs-comment">// Send the template output to </span><span class="cs-comment">// the current selection</span>
selection.MoveTo(selection.CurrentLine, <span class="cs-literal">1</span>, <span class="cs-keyword">false</span>);
selection.Text = target.ToString();</pre>
														<h2>Conclusion</h2>
														<p>Hopefully this article shows that you don’t need to write a complex client for TaHoGen in order for it to be useful. If you’ve read both of my articles on TaHoGen up to this point (including this one) and studied the sample code, then that’s all you’ll really need to know in order for you to get started. Good Luck!</p>
														<h2>Points of Interest</h2>
														<p>What surprised me about writing a simple COM-based add-in like this one was the amount of trouble it gave me when I had to deploy it on other people’s machines; it was a nightmare. Fortunately, I came across MutantDesign’s Managed AddIns which really made it easy to write a decent add-in in just a couple hundred lines of code. My hat is off to MutantDesign!</p>
														<h2>Special Thanks</h2>
														<ul>
																<li>
																		<b>Phil Wright</b>. Thanks for your effort in writing MagicLibrary! 
</li>
																<li>
																		<b>MutantDesign</b>. I truly have to thank you guys for making this add-in easier to write. You have no idea how much trouble you saved me. </li>
														</ul>
												</div>
										</span>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cnitblog.com/MartinYao/aggbug/22638.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/MartinYao/" target="_blank">玄铁剑</a> 2007-02-03 22:40 <a href="http://www.cnitblog.com/MartinYao/articles/22638.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>An Open Source Implementation of a CodeSmith-Style Code Generation Engine</title><link>http://www.cnitblog.com/MartinYao/articles/22637.html</link><dc:creator>玄铁剑</dc:creator><author>玄铁剑</author><pubDate>Sat, 03 Feb 2007 14:34:00 GMT</pubDate><guid>http://www.cnitblog.com/MartinYao/articles/22637.html</guid><wfw:comment>http://www.cnitblog.com/MartinYao/comments/22637.html</wfw:comment><comments>http://www.cnitblog.com/MartinYao/articles/22637.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/MartinYao/comments/commentRss/22637.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/MartinYao/services/trackbacks/22637.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 15 votes for this article.																																																																																																																																																																		...&nbsp;&nbsp;<a href='http://www.cnitblog.com/MartinYao/articles/22637.html'>阅读全文</a><img src ="http://www.cnitblog.com/MartinYao/aggbug/22637.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/MartinYao/" target="_blank">玄铁剑</a> 2007-02-03 22:34 <a href="http://www.cnitblog.com/MartinYao/articles/22637.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>