【问题标题】:TemplateFileManager throws NullReferenceException in TextTemplatingFilePreprocessor modeTemplateFileManager 在 TextTemplatingFilePreprocessor 模式下抛出 NullReferenceException
【发布时间】:2019-04-01 06:42:55
【问题描述】:

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

经过进一步调试,发现TextTemplate实例在TextTemplatingFilePreprocessor模式下没有正确创建。

问题

TemplateFileManagerTextTemplatingFilePreprocessor模式下如何使用?

代码

模板1.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

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

在主函数中

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();

【问题讨论】:

  • 您是否将文件的Custom Tools 属性设置为TextTemplatingFilePreprocessor
  • @OlivierSamson 是的
  • 你试过Walkthrough: Creating a Custom Text Template Host吗?对宿主的属性/方法有相当好的解释
  • @Thundter 我得试试
  • @Thundter 现在Host.AsIServiceProvider() 返回null。我已经更新了我的帖子

标签: c# t4


【解决方案1】:

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

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

<#
    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 做实验。在此之前我也尝试过该管理器文件。

【讨论】:

    猜你喜欢
    • 2013-05-30
    • 2014-03-23
    • 2020-11-17
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多