热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

一起谈.NET技术,编写T4模板无法避免的两个话题:quot;AssemblyLockingquot;amp;quot;Debugquot;...

在这之前,我写了一系列关于代码生成和T4相关的文章,而我现在也试图将T4引入我们自己的开发框架。在实践中遇到了一些问题,也解决了不少问题。

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

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

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

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

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

<#&#64; template debug&#61;"true" hostSpecific&#61;"true" #>
<#&#64; output extension&#61;".cs" #>
<#&#64; Assembly name&#61;"$(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}!", "<#&#61;person#>");
<# } #>
}
}

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

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

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

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

<#&#64; template debug&#61;"true" hostSpecific&#61;"true" #>
<#&#64; output extension&#61;".cs" #>
<#&#64; VolatileAssembly processor&#61;"T4Toolbox.VolatileAssemblyProcessor" name&#61;"$(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}!", "<#&#61;person#>");
<# } #>
}
}

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

  三、Debugger.Break导致VS 2010的Crash

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

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

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

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

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

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

<#&#64; template debug&#61;"true" hostSpecific&#61;"true" #>
<#&#64; output extension&#61;".cs" #>
<#&#64; VolatileAssembly processor&#61;"T4Toolbox.VolatileAssemblyProcessor" name&#61;"$(SolutionDir)Lib\Bin\Debug\Artech.T4Template.Lib.dll" #>
<#&#64; import namespace&#61;"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}!", "<#&#61;person#>");
<#} #>
}
}

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

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

image



推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
author-avatar
彭德利
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有