如何在 T4 模板中获取枚举类型

How to get enum type in a T4 template

在编写 T4 文本模板的过程中,我 运行 遇到了一个我正在努力解决的问题。我需要知道我正在处理的枚举类型。

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

这是字节类型的示例枚举

namespace CodeEnumType
{
    public enum MyEnum : byte
    {
        Member1 = 0,
        Member2 = 1,
    }
}

这是我的 T4 文本模板

<#@ 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;
        }
    }
}
#>

注意我写的部分

        //
        // here I would like the enum type
        //

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

我在这里没有使用反射,因为如果程序集没有被编译,Type.GetType() 就不能正常工作。

这个方法应该return你要找的东西。

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

希望对您有所帮助 ;)

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

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;
    }
}

请注意,示例中的正则表达式只是一个非常简单的模式,可能需要进行调整以适应不同的源代码格式。