我有一个 C# regex-parser 程序,其中包含三个文件,每个文件都包含一个静态类:
1) 一个充满字符串字典的静态类
static class MyStringDicts
{
internal static readonly Dictionary<string, string> USstates =
new Dictionary<string, string>()
{
{ "ALABAMA", "AL" },
{ "ALASKA", "AK" },
{ "AMERICAN SAMOA", "AS" },
{ "ARIZONA", "AZ" },
{ "ARKANSAS", "AR" }
// and so on
}
// and some other dictionaries
}
2) 将这些值编译成正则表达式的类
public static class Patterns
{
Public static readonly string StateUS =
@"\b(?<STATE>" + CharTree.GenerateRegex(Enumerable.Union(
AddrVals.USstates.Keys,
AddrVals.USstates.Values))
+ @")\b";
//and some more like these
}
3) 一些基于这些字符串运行正则表达式的代码:
public static class Parser
{
// heavily simplified example
public static GroupCollection SearchStringForStates(string str)
{
return Regex.Match(str,
"^" + Patterns.StateUS,
RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase).Groups;
}
}
我希望能够像使用 T4 模板一样生成 2),因为所有这些串联在每次执行时都是相同的:
@"\b(?<STATE><#=CharTree.GenerateRegex(Enumerable.Union(
AddrVals.USstates.Keys,
AddrVals.USstates.Values)#>)\b";
这行得通,但是如果我创建 MyStringDicts
的新成员,或者从其字典中添加/删除一些值,T4 模板将无法识别它们,直到将 Patterns.cs 从编译中排除并重新编译.由于 Parser
依赖于 Patterns
,这确实不是一个选项 - 我需要 T4 转换来考虑对同一构建中其他文件的更改。
我不想做的事:
- 将
MyStringDicts
拆分到它自己的项目中。我想将文件保存在一个项目中,因为它们是一个逻辑单元。 - 只需将
MyStringDicts
移动到 Patterns.cs 的顶部。我也需要 MyStringDicts 成员用于其他目的(例如,用于字典查找或其他 T4 模板。)
我采纳了建议here关于使用 T4Toolbox 的 VolatileAssembly
等,但这似乎只适用于反向,当类文件需要在编辑 T4 模板后重新编译时。
我想要的是可能的吗?
为清晰起见进行了编辑
最佳答案
我刚刚创建了一个小型测试模板,它使用 EnvDte(Visual Studio 自动化)和 T4Toolbox 来运行第一个文件。它通过项目获取文件,因此在运行模板之前无需编译。事实上,它甚至可以获取未保存的更改...
这基本上与 FullSnabel 使用的方法相同,但不需要 Roslyn。
<#@ template debug="false" hostspecific="True" language="C#" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ dte processor="T4Toolbox.DteProcessor" #>
<#@ TransformationContext processor="T4Toolbox.TransformationContextProcessor" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="EnvDTE80" #>
<#@ import namespace="T4Toolbox" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="EnvDTE80" #>
<#
ProjectItem projectItem = TransformationContext.FindProjectItem("Dictionaries.cs");
FileCodeModel codeModel = projectItem.FileCodeModel;
foreach (CodeElement element in codeModel.CodeElements)
{
CodeNamespace ns = element as CodeNamespace;
if(ns != null)
{
foreach(CodeElement ele in ns.Children)
{
CodeClass cl = ele as CodeClass;
if(cl != null && cl.Name == "Dictionaries")
{
foreach(CodeElement member in cl.Members)
{
// Generate stuff...
this.WriteLine(member.Name);
}
}
}
}
}
#>
如果您想坚持原来的方法,这应该可行。
您似乎在做的是将数据存储在类文件中。您可以考虑将列表存储在代码之外(在 xml 或 ini 文件中)并根据该数据生成这两个文件。这样你就可以一起避免这个问题,它也可以使管理列表更容易。 如果您不太关心列表的更改,您也可以将字典放在 T4 模板本身中。
另一种选择可能完全在代码中处理它。您可以创建具有“Pattern”属性(或 GetPattern() 函数)的 Dictionary 的子类。然后解析器将使用 AddrVals.USstates.Pattern,并且不再需要模式类。这样您就不需要任何代码生成。
也许实际字典的包装器会更好,因为它允许您隐藏实际集合以确保它在运行时不被更改。参见 Is there a read-only generic dictionary available in .NET?举个例子。
关于c# - 同类代码文件修改后生成T4文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11231281/