在这之前,我写了一系列关于代码生成和T4相关的文章,而我现在也试图将T4引入我们自己的开发框架。在实践中遇到了一些问题,也解决了不少问题。如果你也在进行T4相关的开发,相信你也一定会遇到这些问题。为此,特意将这些问题和解决方案与朋友们分享,希望在遇到这些问题的时候少走弯路。本篇文章介绍的是两个重要的话题:程序集锁定和调试。

目录
一、程序集引用导致的编译问题
二、T4引擎对引用程序集的锁定
三、Debugger.Break导致VS 2010的Crash
四、在Debugger.Break之前加上Debugger.Launch

  一、程序集引用导致的编译问题

  为了让读者对“程序集锁定”,以及由它造成的开发上的不便有一个深刻的认识,我特意写了一个小例子。如右图所示的解决方案包含两个项目:Lib和T4。其中我们的T4项目中定义了一个叫作HelloWorld.tt的模板文件,该文件需要使用到定义在Lib项目中的某个类型。所以,HelloWorld.tt模板文件中需要通过<#@Assembly…#>指令引用Lib项目编译生成的程序集(Artech.T4Template.Lib.dll)。

  如果你看过我上一篇文章,你应该知道我们至少具有解决T4模板的程序集引用的五种方案,在这里我们采用的是VS宏的解决方案,即将引用程序集文件的路径设置成通过$(SolutionDir)表示的解决方案目录的相对路径。HelloWorld.tt定义如下,引用的程序集路径为Lib项目在Debug模式下编译生成的目录($(SolutionDir)Lib\Bin\Debug\)。

<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ Assembly name="$(SolutionDir)Lib\Bin\Debug\Artech.T4Template.Lib.dll" #>
using System;
public class HelloWord
{
static void Main()
{
<# foreach( var person in Artech.T4Template.HelloWorldHelper.GetPersons())
{#>
Console.WriteLine("Hello, {0}!", "<#=person#>");
<# } #>
}
}

  当你保存该T4模板,T4引擎将触发并进行代码生成工作,但是此时如果你试图编译被引用(实际上是生成的程序集被引用)的Lib项目,将会出现如下所示的编译错误。错误信息为:“Unable to copy file "obj\Debug\Artech.T4Template.Lib.dll" to "bin\Debug\Artech.T4Template.Lib.dll". The process cannot access the file 'bin\Debug\Artech.T4Template.Lib.dll' because it is being used by another process.”,即之前生成的程序集正在被使用,所以不能将生成的程序集拷贝到编译目标目录下。

  二、T4引擎对引用程序集的锁定

  实际上这个程序集的使用者正是T4引擎。出于提高性能考虑,T4引擎在进行基于代码生成的模板转换(Template Transformation)的时候,会始终重用同一个AppDomain。由于该AppDomain不会自动卸载,这就会导致该AppDomain始终锁定所有被它加载的程序集。如果我们需要释放程序集,我们不得不重启VS。但是,对于T4模板的开发调试阶段,这种通过重新启动VS的方式去释放程序集以确保我们的项目能够成功编译是不能接受的。

  那么,是否有一种解决方案既能够确保T4引擎能够进行正常的模板转换,又能避免它强行锁定引用程序集呢?如果你采用T4 ToolBox,你可以通过<#@ VolatileAssembly…#>这个指令轻松地解决这个问题。下面的T4模板中,我们将通过<#@Assembly…#>指令的程序集引用方式替换成了<#@ VolatileAssembly…#>(<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor"  name="$(SolutionDir)Lib\Bin\Debug\Artech.T4Template.Lib.dll" #>),我们的Lib项目在任何时候都可以自由地编译。

<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="$(SolutionDir)Lib\Bin\Debug\Artech.T4Template.Lib.dll" #>
using System;
public class HelloWord
{
static void Main()
{
<# foreach( var person in Artech.T4Template.HelloWorldHelper.GetPersons())
{#>
Console.WriteLine("Hello, {0}!", "<#=person#>");
<# } #>
}
}

  <#@ VolatileAssembly…#>的实现原理其实挺简单的,就是在加载的时候并不是直接加载指定的源程序集,而是创建一个新的程序集拷贝。

  三、Debugger.Break导致VS 2010的Crash

  VS和一些T4编辑器虽然给了基本的智能感知支持,但是在绝大部分我们相当于在编写纯文本的脚本,所以对于一些比较复杂的模板转换逻辑,我们需要通过Debug的方式去发现一些无法避免的问题。关于T4模板的Debug,你Google一下会搜出一大堆。在这些“大众化”的Debug解决方案中都包含两点:

  • 在<#@ template…#>指令中将debug属性设置为true;
  • 在需要设置断点的地方执行Debugger.Break方案

  按照这两点,我们改写了我们的T4模板,在foreach语句之前加上<# Debugger.Break(); #>,并通过<#@import…#>指令导入System.Diagnostics命名空间。我不知道在VS 2008下这种解决方案是否可行,但是如果你使用的是VS 2010,这肯定会导致整个VS的崩溃。当你保存TT文件的时候,如右图所示的对话框弹出来,随之伴随整个VS的Crash。

<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="$(SolutionDir)Lib\Bin\Debug\Artech.T4Template.Lib.dll" #>
<#@ import namespace="System.Diagnostics" #>
using System;
public class HelloWord
{
static void Main()
{
<# Debugger.Break(); #>
<# foreach( var person in Artech.T4Template.HelloWorldHelper.GetPersons())
{#>
Console.WriteLine("Hello, {0}!", "<#=person#>");
<# } #>
}
}

  四、在Debugger.Break之前加上Debugger.Launch

  为了避免Debugger.Break导致的VS崩溃,只需要在之前多加一句代码即可,既Debugger.Launch。为此我们对我们的T4模板略加修改:

<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="$(SolutionDir)Lib\Bin\Debug\Artech.T4Template.Lib.dll" #>
<#@ import namespace="System.Diagnostics" #>
using System;
public class HelloWord
{
static void Main()
{
<#
Debugger.Launch();
Debugger.Break();
foreach( var person in Artech.T4Template.HelloWorldHelper.GetPersons())
{#>
Console.WriteLine("Hello, {0}!", "<#=person#>");
<#} #>
}
}

  现在如果你保存该TT文件,VS会弹出如下一个对话框让你选在是否进行Debug。如果需要进行Debug,选择“Yes, debug devenv.exe”。

  然后创建一个新的VS实例,或者选择已经打开的VS程序进行Debug,这个对话框我们应该很熟悉。最后程序将会执行到我们设置的断点(Debugger.Break),我们就可以像Debug普通托管程序一样对T4模板进行Debug了。实际上,你也可以直接通过Attach进程的方式进行Debug,不过这里的进程就是VS的进程devenv.exe。

一起谈.NET技术,编写T4模板无法避免的两个话题:quot;Assembly Lockingquot;amp;quot;Debugquot;...相关推荐

  1. 一起谈.NET技术,Visual Studio自定义调试窗体两个小技巧

    本文翻译:Few Tips on Customizing Debugging Window View in Visual Studio . 使用DebuggerBrowsable特性可以自定义调试窗体 ...

  2. 创建代码生成器可以很简单:如何通过T4模板生成代码?[下篇]

    在<上篇>中我们通过T4模板为我们指定的数据表成功生成了我们需要的用于添加.修改和删除操作的存储过程.但是这是一种基于单个文件的解决方案,即我们必须为每一个生成的存储过程建立一个模板.如果 ...

  3. 快速开发框架,及库存管理系统,基于easyui框架和C#语言MVC、EntityFrameWork、T4模板技术。...

    快速开发框架,及库存管理系统,基于easyui框架和C#语言MVC.EntityFrameWork.T4模板技术. 产品界面如下图所示: 源码结构: 开放全部源码,如有需要请联系,QQ:1107141 ...

  4. 从零开始编写自己的C#框架(14)——T4模板在逻辑层中的应用(三)

    原本关于T4模板原想分5个章节详细解说的,不过因为最近比较忙,也不想将整个系列时间拉得太长,所以就将它们整合在一块了,可能会有很多细节没有讲到,希望大家自己对着代码与模板去研究. 本章代码量会比较大, ...

  5. 一起谈.NET技术,专访微软MVP衣明志:走进ASP.NET MVC 2框架开发

    日前微软已经发布ASP.NET MVC 2框架RC版,究竟这次RC版本的发布对于WEB开发者带来怎样的改变?以及未来ASP.NET MVC 2正式版还会有哪些改进?带着这样的问题,我们51CTO记者彭 ...

  6. 浅谈 CRTP:奇异递归模板模式

    浅谈 CRTP:奇异递归模板模式 前言 建议先看一遍文末的参考资料! 建议先看一遍文末的参考资料! 建议先看一遍文末的参考资料! 思维导图 一.CRTP 是什么 CRTP 全称 : Curiously ...

  7. t4b代码生成_Ef+T4模板实现代码快速生成器

    效果如图,demo(点击demo可下载案例) 项目结构如图 T4BLL添加BLL.tt文件: T4Model添加Model文件: T4DAL添加DAL.tt文件: T4DAL 添加ADO.NET En ...

  8. [转]MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码

    本文转自:http://www.cnblogs.com/guomingfeng/p/mvc-ef-t4.html 〇.目录 一.前言 二.工具准备 三.T4代码生成预热 (一) 单文件生成:Hello ...

  9. php模板技术smarty,PHP模板技术Smarty

    基本信息 讲师: 高洛峰 时长:60分钟 集数:9 每集定价:20 元 描述: 如果你正在设计一个交互式的网站,你一定会关注两个主要的问题,就是界面美工和应用程序.在大多数的项目组中,开发一个Web程 ...

最新文章

  1. MySQL技术内幕 InnoDB存储引擎 之 InnoDB体系架构
  2. 2016年我国研究的超级计算机,盘点2016:我国科研取得的重大成果
  3. 阶乘和(n比较大---大数乘法+大数加法)
  4. java ee基础知识_Java EE:基础知识
  5. JavaEE班第四天
  6. 他人笑我太疯癫 我笑他人看不穿
  7. 【转载】产品经理如何行之有效的提高执行力
  8. 详解如何实现斗鱼、B站等全局悬浮窗直播小窗口
  9. WinForm主窗口框架的设计
  10. PKM全民推广系列三:PKM搜索
  11. python支持xp系统吗_《xp python安装教程》 win XP的系统应该装哪个python的安装包?...
  12. 易语言获取硬盘特征字序列号加密特征字
  13. 各种音视频编解码学习详解之 编解码学习笔记(九):QuickTime系列
  14. 新浪UC聊天室的几个漏洞
  15. 微信公共号分享链接配置
  16. 安卓常用6种设计模式总结
  17. 人脸扫描建模_黑科技 | 3D人脸建模可以多简单?一张照片就搞定!
  18. 布法罗计算机专业怎么样,布法罗大学 University at Buffalo
  19. UART串口流控制(Flow control)
  20. 数据结构之线索二叉树详细解释

热门文章

  1. jquery 如何动态添加、删除class样式方法介绍_jquery_脚本之家
  2. 【Basking Rootwalla】真正理解setup time/hold time(二)
  3. Python学习笔记之变量
  4. 简单的根据parentId生成树
  5. mysql炸包_炸裂!MySQL 82 张图带你飞
  6. 接口和抽象类有什么区别?
  7. 群辉安装失败 找不到服务器,synology NAS 存储安装DSM的方法
  8. 编译型和解释型语言的区别
  9. java中位操作_Java中使用位操作的几个小技巧
  10. Shell命令-文件及内容处理之grep(egrep)、join