关于C#:如何在t4模板中获取枚举类型

How to get enum type in a T4 template

在编写一个t4文本模板的过程中,我遇到了一个问题,我很难通过。我需要知道我正在处理的枚举的类型。

我有基于byteushort的枚举。我需要T4文本模板来编写代码,将枚举强制转换为正确的值类型,以便序列化枚举并将其放入字节数组中。

这是byte类型的枚举示例

1
2
3
4
5
6
7
8
namespace CodeEnumType
{
    public enum MyEnum : byte
    {
        Member1 = 0,
        Member2 = 1,
    }
}

这是我的t4文本模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<#@ template hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="EnvDte" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System.Collections.Generic" #>
<#
var serviceProvider = this.Host as IServiceProvider;
var dte = serviceProvider.GetService(typeof(DTE)) as DTE;
var project = dte.Solution.FindProjectItem(this.Host.TemplateFile).ContainingProject as Project;
var projectItems = GetProjectItemsRecursively(project.ProjectItems);
foreach(var projectItem in projectItems)
{
    var fileCodeModel = projectItem.FileCodeModel;
    if(fileCodeModel == null)
    {
        continue;
    }

    CodeElements codeElements = fileCodeModel.CodeElements;
    ProcessCodeElements(codeElements);
}
#>
<#+
public void ProcessCodeElements(CodeElements codeElements)
{
    if(codeElements == null)
    {
        return;
    }

    foreach(CodeElement codeElement in codeElements)
    {
        switch(codeElement.Kind)
        {
            case vsCMElement.vsCMElementNamespace:
                CodeNamespace codeNamespace = codeElement as CodeNamespace;
                CodeElements childCodeElements = codeNamespace.Members;
                ProcessCodeElements(childCodeElements);
                break;
            case vsCMElement.vsCMElementEnum:
                CodeEnum codeEnum = codeElement as CodeEnum;
                WriteLine(codeEnum.Name);
                //
                // here I would like the enum type
                //
                break;
        }
    }
}
public IEnumerable<ProjectItem> GetProjectItemsRecursively(ProjectItems items)
{
    if(items == null)
    {
        yield break;
    }

    foreach(ProjectItem item in items)
    {
        yield return item;

        var childItems = GetProjectItemsRecursively(item.ProjectItems);
        foreach(ProjectItem childItem in childItems)
        {
            yield return childItem;
        }
    }
}
#>

注意我写的部分

1
2
3
        //
        // here I would like the enum type
        //

这里我在变量codeEnum中有枚举信息,这就是我的问题所在。如何从codeEnum中获得byteushort类型?

我没有在这里将反射用作类型。如果程序集尚未编译,getType()将无法正常工作。


envdte对象模型未公开基础枚举类型。作为解决方法,可以检索枚举类型定义的源代码并解析基类型,例如使用正则表达式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
foreach(CodeElement codeElement in codeElements)
{
    switch(codeElement.Kind)
    {
        case vsCMElement.vsCMElementNamespace:
            CodeNamespace codeNamespace = codeElement as CodeNamespace;
            CodeElements childCodeElements = codeNamespace.Members;
            ProcessCodeElements(childCodeElements);
            break;
        case vsCMElement.vsCMElementEnum:
            CodeEnum codeEnum = codeElement as CodeEnum;
            Write(codeEnum.Name);

            // get the source code of the enum
            string sourceCodeEnum =
                codeEnum.StartPoint.CreateEditPoint().GetText(codeEnum.EndPoint);

            // a regular expression capturing the base type
            System.Text.RegularExpressions.Regex regex
                = new System.Text.RegularExpressions.Regex(
                    @"\benum .*\s*\:\s*(?<underlyingType>\w*)");

            var match = regex.Match(sourceCodeEnum);
            if (match.Success)
            {
                WriteLine(" :" + match.Groups["underlyingType"].Value);
            }

            break;
    }
}

请注意,示例中的regex只是一个非常简单的模式,可能需要调整它来处理不同的源代码格式。


此方法应返回您要查找的内容。

1
2
3
4
5
static Type GetEnumType<T>() where T : struct, IComparable
{
    var ti = (TypeInfo)typeof(T);
    return ti.DeclaredFields.First().FieldType;
}

希望这有帮助;)