TemplateFileManager在TextTemplatingFilePreprocessor模式下引发NullReferenceException

时间:2019-04-01 06:42:55

标签: c# t4

我想使用T4模板创建多个文件。因此,我正在使用TemplateFileManagerV2.1.ttinclude文件来执行此操作。在TextTemplatingFileGenerator模式(设计时间)下,它可以正常工作。我需要运行时生成,因此我将模式更改为TextTemplatingFilePreprocessor。现在我的程序抛出NullReferenceException

enter image description here

进一步调试后,我发现在TextTemplatingFilePreprocessor模式下不能正确创建TextTemplate实例。

enter image description here

enter image description here

问题

如何在TemplateFileManager模式下使用TextTemplatingFilePreprocessor

代码

Template1.tt

<#@ template language="C#" debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ include file="TemplateFileManagerV2.1.ttinclude" #>
<#@ Assembly Name="System.Core" #>
<#@ Assembly Name="System.Windows.Forms" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #> 
<#
   string Greeting = "Hello";
   var manager = TemplateFileManager.Create(this);
   manager.StartNewFile(Path.Combine(Path.GetDirectoryName(this.Host.TemplateFile), "Outputfile2.cs"));
#>
namespace MyNameSpace{
  class MyGeneratedClass{
     static void main (string[] args){
       System.Console.WriteLine("<#= Greeting #>, the time is now: <#= System.DateTime.Now.ToString() #>");
     }
  }
}
<#
    manager.Process();
#>

运行T4模板的代码

var page = new Template1();
var pageContent = page.TransformText();

尝试过的解决方法

手动设置Host。现在Host.AsIServiceProvider()返回null

enter image description here

public class TextTemplatingEngineHost : ITextTemplatingEngineHost
{
    internal string TemplateFileValue;
    public string TemplateFile
    {
        get { return TemplateFileValue; }
    }
    public string FileExtension { get; private set; } = ".cs";
    public Encoding FileEncoding { get; private set; } = Encoding.UTF8;
    public CompilerErrorCollection Errors { get; private set; }

    public IList<string> StandardAssemblyReferences
    {
        get
        {
            return new string[]
            {
                typeof(System.Windows.Forms.AccessibleEvents).Assembly.Location
            };
        }
    }

    public IList<string> StandardImports
    {
        get
        {
            return new string[]
            {
                "System",
                "System.IO",
                "System.Diagnostics",
                "System.Linq",
                "System.Collections",
                "System.Collections.Generic"
            };
        }
    }

    public bool LoadIncludeText(string requestFileName, out string content, out string location)
    {
        content = string.Empty;
        location = string.Empty;

        if (File.Exists(requestFileName))
        {
            content = File.ReadAllText(requestFileName);
            return true;
        }
        else
        {
            return false;
        }
    }

    public object GetHostOption(string optionName)
    {
        object returnObject;
        switch (optionName)
        {
            case "CacheAssemblies":
                returnObject = true;
                break;
            default:
                returnObject = null;
                break;
        }
        return returnObject;
    }

    public string ResolveAssemblyReference(string assemblyReference)
    {

        if (File.Exists(assemblyReference))
        {
            return assemblyReference;
        }

        string candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), assemblyReference);
        if (File.Exists(candidate))
        {
            return candidate;
        }
        return "";
    }

    public Type ResolveDirectiveProcessor(string processorName)
    {
        if (string.Compare(processorName, "XYZ", StringComparison.OrdinalIgnoreCase) == 0)
        {
            //return typeof();
        }

        throw new Exception("Directive Processor not found");
    }

    public string ResolvePath(string fileName)
    {
        if (fileName == null)
        {
            throw new ArgumentNullException("the file name cannot be null");
        }

        if (File.Exists(fileName))
        {
            return fileName;
        }

        string candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), fileName);
        if (File.Exists(candidate))
        {
            return candidate;
        }

        return fileName;
    }

    public string ResolveParameterValue(string directiveId, string processorName, string parameterName)
    {
        if (directiveId == null)
        {
            throw new ArgumentNullException("the directiveId cannot be null");
        }
        if (processorName == null)
        {
            throw new ArgumentNullException("the processorName cannot be null");
        }
        if (parameterName == null)
        {
            throw new ArgumentNullException("the parameterName cannot be null");
        }

        return String.Empty;
    }

    public void SetFileExtension(string extension)
    {
        FileExtension = extension;
    }

    public void SetOutputEncoding(Encoding encoding, bool fromOutputDirective)
    {
        FileEncoding = encoding;
    }

    public void LogErrors(CompilerErrorCollection errors)
    {
        Errors = errors;
    }

    public AppDomain ProvideTemplatingAppDomain(string content)
    {
        return AppDomain.CreateDomain("Generation App Domain");
    }
}

在Main函数中

var templateFileName = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())), "Template1.tt");

var host = new TextTemplatingEngineHost();
host.TemplateFileValue = templateFileName;

var template = new Template1();
template.Host = host;
var output = template.TransformText();

1 个答案:

答案 0 :(得分:0)

您可以轻松地将输出写入特定文件,并防止模板使用几行代码将输出写入子节点。

将以下代码添加到模板的底部,或者在编写多个文件时在迭代结束时添加

<#
    SaveFile(entitiesFolder, entity.Name, this.GenerationEnvironment.ToString());
    this.GenerationEnvironment.Remove(0, this.GenerationEnvironment.Length); //Removes the output
#> 

SaveFile方法只是一个写入特定文件夹或路径的streamWriter。

public void SaveFile(string folder, string fileName, string content)
{
    using (FileStream fs = new FileStream(Path.Combine(folder, fileName.Trim() + ".cs"), FileMode.Create))
    {
        using (StreamWriter str = new StreamWriter(fs))
        {
            str.WriteLine(content);
            str.Flush();
        }
    }
}

我尝试了这个here。在此之前,我还尝试了该管理器文件。