天天看點

一起談.NET技術,編寫T4模闆無法避免的兩個話題:"Assembly Locking"&"Debug"  一、程式集引用導緻的編譯問題  三、Debugger.Break導緻VS 2010的Crash  四、在Debugger.Break之前加上Debugger.Launch

  在這之前,我寫了一系列關于代碼生成和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)。

一起談.NET技術,編寫T4模闆無法避免的兩個話題:"Assembly Locking"&"Debug"  一、程式集引用導緻的編譯問題  三、Debugger.Break導緻VS 2010的Crash  四、在Debugger.Break之前加上Debugger.Launch

<#@ 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.”,即之前生成的程式集正在被使用,是以不能将生成的程式集拷貝到編譯目标目錄下。

一起談.NET技術,編寫T4模闆無法避免的兩個話題:"Assembly Locking"&"Debug"  一、程式集引用導緻的編譯問題  三、Debugger.Break導緻VS 2010的Crash  四、在Debugger.Break之前加上Debugger.Launch

  實際上這個程式集的使用者正是T4引擎。出于提高性能考慮,T4引擎在進行基于代碼生成的模闆轉換(Template Transformation)的時候,會始終重用同一個AppDomain。由于該AppDomain不會自動解除安裝,這就會導緻該AppDomain始終鎖定所有被它加載的程式集。如果我們需要釋放程式集,我們不得不重新開機VS。但是,對于T4模闆的開發調試階段,這種通過重新啟動VS的方式去釋放程式集以確定我們的項目能夠成功編譯是不能接受的。

<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="$(SolutionDir)Lib\Bin\Debug\Artech.T4Template.Lib.dll" #>

  <#@ VolatileAssembly…#>的實作原理其實挺簡單的,就是在加載的時候并不是直接加載指定的源程式集,而是建立一個新的程式集拷貝。

  VS和一些T4編輯器雖然給了基本的智能感覺支援,但是在絕大部分我們相當于在編寫純文字的腳本,是以對于一些比較複雜的模闆轉換邏輯,我們需要通過Debug的方式去發現一些無法避免的問題。關于T4模闆的Debug,你Google一下會搜出一大堆。在這些“大衆化”的Debug解決方案中都包含兩點:

一起談.NET技術,編寫T4模闆無法避免的兩個話題:"Assembly Locking"&"Debug"  一、程式集引用導緻的編譯問題  三、Debugger.Break導緻VS 2010的Crash  四、在Debugger.Break之前加上Debugger.Launch

在<#@ template…#>指令中将debug屬性設定為true;

  按照這兩點,我們改寫了我們的T4模闆,在foreach語句之前加上<# Debugger.Break(); #>,并通過<#@import…#>指令導入System.Diagnostics命名空間。我不知道在VS 2008下這種解決方案是否可行,但是如果你使用的是VS 2010,這肯定會導緻整個VS的崩潰。當你儲存TT檔案的時候,如右圖所示的對話框彈出來,随之伴随整個VS的Crash。

<#@ import namespace="System.Diagnostics" #>

<# Debugger.Break(); #>

  為了避免Debugger.Break導緻的VS崩潰,隻需要在之前多加一句代碼即可,既Debugger.Launch。為此我們對我們的T4模闆略加修改:

<#

Debugger.Launch();

Debugger.Break();

foreach( var person in Artech.T4Template.HelloWorldHelper.GetPersons())

<#} #>

  現在如果你儲存該TT檔案,VS會彈出如下一個對話框讓你選在是否進行Debug。如果需要進行Debug,選擇“Yes, debug devenv.exe”。

一起談.NET技術,編寫T4模闆無法避免的兩個話題:"Assembly Locking"&"Debug"  一、程式集引用導緻的編譯問題  三、Debugger.Break導緻VS 2010的Crash  四、在Debugger.Break之前加上Debugger.Launch
一起談.NET技術,編寫T4模闆無法避免的兩個話題:"Assembly Locking"&"Debug"  一、程式集引用導緻的編譯問題  三、Debugger.Break導緻VS 2010的Crash  四、在Debugger.Break之前加上Debugger.Launch

繼續閱讀