2010年9月19日星期日

Visual Studio T4 中定位当前Solution的技巧

Visual Studio 中的T4模板可以极其方便的利用代码生成代码、配置或者任何需要生成的内容。
其实T4从VS08开始似乎就内置了支持,在VS05下似乎也可以用插件的方式添加支持。而在VS10下,还有了专门的T4的Editor的Extension。
然而虽然支持的增强,但是T4似乎被MSFT认定为DSL的技术,似乎有些小众,所以并没有被广泛的推广,资料也特别的少和难找。MSDN上的内容基本都和DSL有关,远远超出了做基本代码生成模板的需求。

按照我摸索的经验,把T4模板作为代码IDE内置的轻量级的代码生成工具使用是,存在一个致命的缺陷,就是模板和其容器缺乏一个很方便的数据输入的通用通道,因此Template内无法获取到当前文件的路径等基本信息,这对资源的引用带来了一定程度的麻烦。
一般来说为了模板的泛用性,一半都会把HostSpecific设置为False,这时,TextTransform对象是没有Host属性的,因此没有办法获知当前Solution或者Project的文件路径信息,同时也就无法获取到同一个Solution或者Project下的其他相关文件。
然而即使把HostSpecific设置为True,也存在巨大的问题,因为一般来说代码的Build环境和Development环境是不一样的,Build Team很少会利用Visual Studio去编译代码。
因此MSDN教授的利用VS API的方法的泛用新非常差:

<#@ template debug="false" hostspecific="true" language="C#" #> ... <#@ assembly name="EnvDTE" #> ... EnvDTE.DTE dte = (EnvDTE.DTE) ((IServiceProvider) this.Host) .GetService(typeof(EnvDTE.DTE)); // Open the prototype document. XmlDocument doc = new XmlDocument(); doc.Load(System.IO.Path.Combine(dte.ActiveDocument.Path, "exampleXml.xml"));

这段代码利用EnvDTE去获取当前的文件路径,其实适用性非常差。

经过研究,我发现了一个更加方便和靠谱的方式:
可以利用反射和Assembly Reference机制去定位Solution的文件位置。
首先在自己的Solution中加入一个.net的Assembly,可以为DLL或者Exe,我们把这个文件叫做Location Reference Assembly(LRA)
然后在T4模板中利用引用该Assembly。由于assembly 的引用指令支持 VS 环境变量 ,因此我们可以利用$(SolutionDir)的值和相对路径去定位LRA。
然后在T4模板的代码中利用反射获取LRA的Assembly对象,然后从Assembly.Location属性就是LRA的绝对地址。
这时在利用Path.Combine就可以获取到$(SolutionDir)的值。
随后就能取到任何Project Item的Path了~

实例代码如下:SolutionVersionConvertUtilility.exe是我Solution里的一个用于进行VS10和VS08的Solution文件互转的工具,这里被我当作了LRA使用

<#@ assembly Name="$(SolutionDir)Debug Scripts\SolutionVersionConvertUtilility.exe" #> 

<#
public string SolutionPath{ get { return Path.Combine(System.Reflection.Assembly.GetAssembly(typeof(Windy.Utilities.SolutionVersionConversion.SolutionVersionConverter)).Location,".."); } }
#>

SolutionPath就可以很好的获取到Solution的文件夹路径!

TimNew
------------
Release your passion
To Realize your potential

Posted via email from 米良的草窝

没有评论:

发表评论