Accessing Attributes using EnvDTE

时间:2019-01-18 19:12:13

标签: c# t4 envdte

I am currently trying to generate some classes based on interfaces using t4. For this purpose, I employ EnvDTE to parse my source code. Getting classes and properties works fine, but for some reason I cannot access their respective attributes.

My interface looks like this:

namespace TestProject.Model
{
    [SQLModel]
    public interface IEntity
    {
        [PrimaryKey, AutoIncrement, NotNull]
        long? Id { get; set; }
    }
}

And the t4 template like this:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".txt" #>
<#@ assembly name="System" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data.Entity" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO"#>
<#@ import namespace="EnvDTE" #>
<#@ include file="T4Toolbox.tt" #>
<#

string targetNamespace = "TestProject";
var dte = (DTE)TransformationContext.Current.GetService(typeof(DTE));
var project = dte.Solution.FindProjectItem(TransformationContext.Current.Host.TemplateFile).ContainingProject;

var classes = FindModelInterfaces(project, targetNamespace, "");

foreach (CodeInterface c in classes) { 

    var className = GetClassName(c);

#>
public partial class <#= className #> {

<#
    IEnumerable<CodeProperty> properties = c.Members.OfType<CodeProperty>()
        .Where(p => p.Access.HasFlag(vsCMAccess.vsCMAccessPublic))
        .OrderBy(p => p.Name);

    foreach (CodeProperty prop in properties) {

        var attributes = prop.Attributes.OfType<CodeAttribute>();

        foreach (CodeAttribute attribute in attributes) {
        #>
        <#= attribute.Name #>
        <#
        }

#>
    public <#= prop.Type.AsString #> <#= prop.Name #> { get; set; }
<#
    }
#>    
}    
<# 
} 
#>


<#+

private string GetClassName(CodeInterface iface) {
    if (!iface.Name.StartsWith("I"))
        throw new Exception();
    return iface.Name.Substring(1);
}

List<CodeInterface> FindModelInterfaces(Project project, string ns, string className) {
    List<CodeInterface> result = new List<CodeInterface>();
    FindClasses(project.CodeModel.CodeElements, className, ns, result, false);
    return result;
}

void FindClasses(CodeElements elements, string className, string searchNamespace, List<CodeInterface> result, bool isNamespaceOk) {
    if (elements == null) return;

    foreach (CodeElement element in elements) {

        if (element is CodeNamespace) {
            CodeNamespace ns = element as CodeNamespace;

            if (ns.FullName.Contains(searchNamespace))
                FindClasses(ns.Members, className, searchNamespace, result, true);
            else
                FindClasses(ns.Members, className, searchNamespace, result, false);

        } else if (element is CodeInterface && isNamespaceOk) {
            CodeInterface c = element as CodeInterface;

            if (c.FullName.Contains(className))
                result.Add(c);

            FindClasses(c.Members, className, searchNamespace, result, true);
        }
    }
}
#>

Even though there clearly are attributes on the Id property, none are returned within the template. What am I doing wrong?

0 个答案:

没有答案