Читать классы в пространстве имен в шаблоне t4 - PullRequest
10 голосов
/ 13 октября 2010

Есть ли способ, которым я могу читать в пространстве имен и перебирать все классы в шаблоне t4, используя отражение или что-то еще?

<#foreach (class poco in LoadNamespace("Web.Code.Entities.Poco").Classes ) { #>
public interface I<# poco.ClassName #>Repository 
{
    IQueryable< <# poco.ClassName #> > Get();
    <# poco.ClassName #> Save(<# poco.ClassName #> entity);
    bool Delete(<# poco.ClassName #> entity);
}
<#} #>

пример метаданных:

namespace Web.Code.Entities.Poco
{
    public class Product
    { 
          public int Id { get; set; }
          public string Name{ get; set; }
          public string Category{ get; set; }
    }

    public class Employee
    { 
          public int Id { get; set; }
          public string Name{ get; set; } 
    }
}

желаемый вывод:

    public interface IProductRepository 
    {
        IQueryable<Product> Get();
        Product Save(Product entity);
        bool Delete(Product entity);
    }   

    public interface IEmployeeRepository 
    {
        IQueryable<Employee> Get();
        Employee Save(Employee entity);
        bool Delete(Employee entity);
    }

Ответы [ 4 ]

13 голосов
/ 27 января 2012

Сначала установите T4Toolbox отсюда

Затем В своем шаблоне убедитесь, что у вас есть следующие строки вверху:

<#@ assembly name="EnvDTE" #> 
<#@ import namespace="EnvDTE" #>
<#@ include file="T4Toolbox.tt" #>

Затем добавьте эти строки кодов:

<#+  

private List<CodeClass> FindClasses(string nameSpace, string className)
{
    List<CodeClass> result=new List<CodeClass>();
    FindClasses(TransformationContext.Project.CodeModel.CodeElements,className,nameSpace,result,false);
    return result;

}


private void FindClasses(CodeElements elements, string className,string searchNamespace,List<CodeClass> result,bool isNamespaceOk)
{
    if (elements==null)return;
    foreach (CodeElement element in elements)
    {       
        if(element is CodeNamespace)
        {
            CodeNamespace ns = element as CodeNamespace;
            if(ns != null)
            {
                if (ns.FullName == searchNamespace)
                    FindClasses(ns.Members, className,searchNamespace,result,true);
                else
                    FindClasses(ns.Members, className,searchNamespace,result,false);
            }
        }
        else if(element is CodeClass && isNamespaceOk)
        {
            CodeClass c = element as CodeClass;
            if (c != null)
            {
                if(c.FullName.Contains(className))
                    result.Add(c);

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

        }
    }
}
#>

Затем вы можете найти все классы в пространстве имен, вызвав их следующим образом (второй параметр фильтрует все классы, имена которых содержат переданную строку):

FindClasses("NameSpace.SubNameSpace",""))//All classes in the specifed namespace 

ИЛИ

FindClasses("NameSpace.SubNameSpace","Repository")) //All classes in the specifed namespace which have "Repository" in their names

------------------------------------------ ОБНОВЛЕНИЕ ДЛЯ VS 2012 --------------------------

Используйте эти функции и пространства имен, если ваш T4Toolbox обновлендля VS 2012:

//visual studio 2012+
<#@ assembly name="Microsoft.VisualStudio.Shell.11.0" #>
<#@ assembly name="Microsoft.VisualStudio.Shell.Interop" #>
<#@ import namespace="Microsoft.VisualStudio.Shell" #>
<#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>

private List<CodeClass> FindClasses(string nameSpace, string className,string baseClassName)
{
    List<CodeClass> result=new List<CodeClass>();
    FindClasses(GetProject().CodeModel.CodeElements,className,baseClassName,nameSpace,result,false);
    return result;

}


private void FindClasses(CodeElements elements, string className,string baseClassName,string searchNamespace,List<CodeClass> result,bool isNamespaceOk)
{
    if (elements==null)return;
    foreach (CodeElement element in elements)
    {       
        if(element is CodeNamespace)
        {
            CodeNamespace ns = element as CodeNamespace;
            if(ns != null)
            {
                if (ns.FullName == searchNamespace)
                    FindClasses(ns.Members, className,baseClassName,searchNamespace,result,true);
                else
                    FindClasses(ns.Members, className,baseClassName,searchNamespace,result,false);
            }
        }
        else if(element is CodeClass && isNamespaceOk)
        {
            CodeClass c = element as CodeClass;
            if (c != null)
            {
                if(c.FullName.Contains(className) && (baseClassName==null || (HasIt(c.Bases ,baseClassName) && c.Name != baseClassName)))
                    result.Add(c);

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

        }
    }
}

private bool HasIt(CodeElements elements,string name)
{
    foreach (CodeElement element in elements)
    {
        if (element.Name==name)
            return true;
    }
    return false;
}

private Project GetProject()
{
    // Get DTE
    var dte = (DTE)TransformationContext.Current.GetService(typeof(DTE));

    // Get ProjectItem representing the template file
    ProjectItem projectItem = dte.Solution.FindProjectItem(TransformationContext.Current.Host.TemplateFile);

    // Get the Project of the template file
    Project project = projectItem.ContainingProject;

    return project;
}

private string GetDefaultNamespace()
{

    // Get DTE
    var dte = (DTE)TransformationContext.Current.GetService(typeof(DTE));

    // Get ProjectItem representing the template file
    ProjectItem projectItem = dte.Solution.FindProjectItem(TransformationContext.Current.Host.TemplateFile);

    // Get the Project of the template file
    Project project = projectItem.ContainingProject;

    var vsSolution = (IVsSolution)TransformationContext.Current.GetService(typeof(SVsSolution));
    IVsHierarchy vsHierarchy;
    ErrorHandler.ThrowOnFailure(vsSolution.GetProjectOfUniqueName(project.FullName, out vsHierarchy));
    uint projectItemId;
    ErrorHandler.ThrowOnFailure(vsHierarchy.ParseCanonicalName(projectItem.FileNames[1], out projectItemId));
    object defaultNamespace;
    ErrorHandler.ThrowOnFailure(vsHierarchy.GetProperty(projectItemId, (int)VsHierarchyPropID.DefaultNamespace, out defaultNamespace));
    return ((string)defaultNamespace);
}

, поэтому ваш поиск будет выглядеть примерно так:

FindClasses(GetDefaultNamespace(),"Repository","RepositoryBase")
2 голосов
/ 08 февраля 2011

Лучше всего использовать VisualModel CodeModel, который является частью API автоматизации DTE. Вы можете получить DTE, сделав свой шаблон HostSpecific, приведя свойство Host к IServiceProvider и затем выполнив вызов GetService ().

Есть пример того, как это сделал Колин Эберхардт на CodeProject: http://www.codeproject.com/Articles/39071/Declarative-Dependency-Property-Definition-with-T4.aspx

1 голос
/ 03 сентября 2016

Я использую T4 в основном проекте .net,

Мой T4 довольно большой, поэтому просто извлекаю соответствующую информацию здесь .. [В моем случае я ищу Entity Framework Models и знаю этиявляются единственными классами в пространстве имен, вам может потребоваться отфильтровать свой собственный]

, ссылающийся на эти пакеты nuget:

<#@ assembly name="$(UserProfile)\.nuget\packages\Microsoft.VisualStudio.TextTemplating.Interfaces.14.0\14.3.25407\lib\net45\Microsoft.VisualStudio.TextTemplating.Interfaces.14.0.dll" #>
<#@ assembly name="$(UserProfile)\.nuget\packages\Microsoft.VisualStudio.TextTemplating.14.0\14.3.25407\lib\net45\Microsoft.VisualStudio.TextTemplating.14.0.dll" #>

эти импорт / включает:

<#@ import namespace="EnvDTE" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating.Interfaces" #>
<#@ include file="$(UserProfile)\.nuget\packages\T4.VsAutomationHelper\1.0.0\tools\ttinc\VsAutomationHelper.CS.ttinclude" #>
<#@ include file="$(UserProfile)\.nuget\packages\T4.TemplateFileManager\2.2.1\tools\ttinc\TemplateFilemanager.CS.ttinclude" #>

У меня есть этот метод:

// Get all CodeClass Items in specified namespace
    public List<EnvDTE.CodeClass> GetClassesInNameSpace(IEnumerable<ProjectItem> items, string nameSpace)
    {
        var classItems = new List<EnvDTE.CodeClass>();

        var csFileProjectItems = items.Where(d => d.Properties.Item("FullPath").Value.ToString().EndsWith(".cs"));

        foreach(ProjectItem csFileProjectItem in csFileProjectItems)
        {
            EnvDTE.FileCodeModel model = csFileProjectItem.FileCodeModel;
            foreach(var modelCodeElements in model.CodeElements)
            {
                if (modelCodeElements is EnvDTE.CodeNamespace)
                {
                    var codeNameSpace = ((EnvDTE.CodeNamespace)modelCodeElements);

                    if (codeNameSpace.FullName == nameSpace)
                    {
                        foreach(var modelCodeElementChild in codeNameSpace.Children)
                        {
                            if (modelCodeElementChild is EnvDTE.CodeClass)
                            {
                                classItems.Add((EnvDTE.CodeClass)modelCodeElementChild);
                            }
                        }
                    }
                }
            }
        }
        return classItems;
    }

и вызовите его, используя: (замените «App.Data.Model.Entities» своим собственным)

    var projectItems = this.dteHelper.GetAllProjectItems();
        var entityClasses = GetClassesInNameSpace(projectItems, "App.Data.Model.Entities");

    foreach (var entityClass in entityClasses)
    {
        // entityClass.Name

        // Important for .NetCore
        // when calling fileManager.StartNewFile() specify all the parameters, its didn't work for me otherwise eg:
        // code appreciated (file manager created before following code)

        var fileProperties = new FileProperties()
{ 
    BuildAction = BuildAction.Compile
};
        fileManager.StartNewFile(dataAccessFileName, generatedFilesTargetProject, generatedFilesTargetFolder, fileProperties);
    fileManager.IsAutoIndentEnabled = true;
    fileManager.CanOverwriteExistingFile = true;
    }
0 голосов
/ 02 сентября 2016
...