T4 Toolbox - Referencing Class in Current Assembly

后端 未结 4 1703
佛祖请我去吃肉
佛祖请我去吃肉 2021-02-19 08:48

I am writing a T4 script which reflects over certain classes and provides code generation based on them. The problem is that my script errors out, saying that the classes in my

相关标签:
4条回答
  • 2021-02-19 09:23

    Reference it common way. Then check if assembly is loaded, if not - generate stub code (to make compilation possible; after compilation run T4 again, to genereate real code). And have unit test that could prevent stub code going to production.

    0 讨论(0)
  • 2021-02-19 09:26

    I believe this is what Nicko and uosɐſ are looking for. Just change the "MyAssembly.CodeGeneration" to the name of the project with the T4 templates.

    <#@ assembly name="$(TargetPath)MyAssembly.dll" #>
    <#@ import namespace="MyAssembly.CodeGeneration" #>
    
    0 讨论(0)
  • 2021-02-19 09:32

    For some reason I couldn't get @brian solution working. I ending up doing this In my case T4Generators was my seperate project in the same solution.

    <#@ assembly name="$(SolutionDir)\T4Generators\bin\Debug\T4Generators.dll" #>
    <#@ import Namespace="T4Generators" #>
    
    0 讨论(0)
  • 2021-02-19 09:36

    One thing to keep in mind is that the T4 script you are writing doesn't actually "reside in the same assembly" - because it is design-time code, not run-time code. In other words - it doesn't get compiled into your assembly at all.

    Instead, the T4 template script is run while you are writing code - or, if you have certain hooks enabled, whenever you build/compile your program. Because it's actually separate from your project, code, though, it has no ability to reference your project's assembly directly - unless you use something like DTE - which gives you the ability to access the Visual Studio environment itself, and explore elements such as the currently-loaded project.

    As an example, consider the following script:

    <#@ template language="C#" debug="false" hostspecific="true" #>
    <#@ output extension=".js" #>
    <#@ assembly name="System" #>
    <#@ assembly name="System.Core" #>
    <#@ assembly name="System.Data.Entity" #>
    <#@ assembly name="EnvDTE" #>
    <#@ import namespace="EnvDTE" #>
    <#@ include file="T4Toolbox.tt" #>
    <#@ import namespace="System" #>
    <#@ import namespace="System.Collections" #>
    <#@ import namespace="System.Collections.Generic" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Reflection" #>
    
    string targetNamespace = "MyNamespace";
    var dte = (DTE)TransformationContext.Current.GetService(typeof(DTE));
    var project = dte.Solution.FindProjectItem(TransformationContext.Current.Host.TemplateFile).ContainingProject);
    
    var classes = FindClasses(project, targetNamespace, "");
    
    <# foreach (CodeClass c in classes) { #>
    
        public class <#= c.Name #> {
    
    <#     var properties = c.Members.OfType<EnvDTE.CodeProperty>()
               .Where(p => p.Access.HasFlag(vsCMAccess.vsCMAccessPublic))
               .OrderBy(p => p.Name);
           foreach (var prop in properties) { 
    #>
    
           public <#= prop.Type.AsString #> <#= prop.Name #> { get; set; }
    
    <#     } #>
    
       }
    
    <# } #>
    
    <#+ List<CodeClass> FindClasses(Project project, string ns, string className) {
            List<CodeClass> result = new List<CodeClass>();
            FindClasses(project.CodeModel.CodeElements, className, ns, result, false);
            return result;
        }
        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);
                    }
                }
            }
        }
    

    This script, in essence, will run through a specific namespace (in this case "MyNamespace"), iterate through all of the classes therein, then output a new code file which lists only their public properties with a getter/setter - in essence, producing a POCO of the objects. In some of my projects, I use an adapted version of this code to generate JavaScript objects based on my POCOs, so that my JS models can always be in-sync with my server-side objects, from a serialization perspective.

    The trick to it, though, is in the first few lines:

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

    In essence, the DTE service is asking Visual Studio to give it an abstract model of the currently-loaded Solution and it's Projects. We then load up the Project in which the current TemplateFile is stored, and in the FindClasses() method, parse out the classes within that project which match our search criteria.

    I hope the example code gives you a starting point to jump off from - but if you need further detail, here are a few additional references for you to sink your teeth into:

    • DTE and T4: Better Together
    • Accessing Visual Studio from a T4 Text Template
    • Accessing Projects via DTE in C# T4 Template
    0 讨论(0)
提交回复
热议问题