【问题标题】:How to get enum type in a T4 template如何在 T4 模板中获取枚举类型
【发布时间】:2016-08-22 11:36:26
【问题描述】:

在编写 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() 将无法正常工作。

【问题讨论】:

  • 为什么要将枚举转换为正确的值类型?
  • 什么是CodeEnum?您实际使用的代码生成技术是 T4 还是 CodeDom?假设Code* 引用 CodeDom 类,这似乎是一种奇怪的混合。
  • 您可能正在寻找这个:msdn.microsoft.com/en-us/library/… 但是,您的问题是模棱两可的。 T4 / CodeDom / 反射?这些是完全不同的概念。
  • @OndrejTucny 看起来提问者有一个the EnvDTE.CodeEnum type 的实例。所以他问如何从中获取底层整数类型,我想。
  • @JeppeStigNielsen 这可能是可能的,但我必须依赖每次更改后已编译一次程序集.. 不是最佳的

标签: c# enums t4 envdte


【解决方案1】:

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

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

【讨论】:

  • 太棒了!我已将最后一个 .* 更改为 \w* 以避免组值末尾的空格。 @"\benum .*\s*\:\s*(?\w*)"。我也不知道\b,这很聪明。谢谢
【解决方案2】:

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

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

希望这会有所帮助;)

【讨论】:

  • 这可能可行,但 OP 正在寻找一种无需反射的解决方案,因为这需要已经编译源代码。
  • @DirkVollmar 正确。我不是在寻找基于反射的解决方案
猜你喜欢
  • 1970-01-01
  • 2017-01-14
  • 1970-01-01
  • 2016-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多