简体   繁体   English

在文本文件中加载和访问模板变量

[英]Loading and accessing template variables inside text file

we have a bunch of text templates that are embedded resources in our visual studio solution. 我们有一堆文本模板,这些模板是Visual Studio解决方案中的嵌入式资源。

I'm using a simple method like this to load them: 我正在使用像这样的简单方法来加载它们:

    public string getTemplate()
    {
        var assembly = Assembly.GetExecutingAssembly();
        var templateName = "ResearchRequestTemplate.txt";
        string result;

        using (Stream stream = assembly.GetManifestResourceStream(templateName))
        using (StreamReader reader = new StreamReader(stream))
        {
            result = reader.ReadToEnd();
        }
        return result;
    }

So I can load the file with the above method, but how do I replace the template variables inside the file with variables I've created in my code? 因此,我可以使用上述方法加载文件,但是如何用在代码中创建的变量替换文件中的模板变量? Is that even possible? 那有可能吗? Maybe I'm going about this all wrong... 也许我要解决所有这些错误...

ResearchRequestTemplate.txt:

Hello { FellowDisplayName }

You have requested access to the { ResearchProjectTitle } Project.

    Please submit all paperwork and badge ID to { ResourceManagerDisplayName }

Thanks! 谢谢!

You could use a series of string.Replace() statements. 您可以使用一系列string.Replace()语句。

Or you could modify the template and make use of string.Format : 或者,您可以修改模板并使用string.Format

Hello {0}

You have requested access to the {1} Project.

    Please submit all paperwork and badge ID to {2}

After you read in the template, insert the correct values: 阅读模板后,请插入正确的值:

return string.Format(
    result, fellowDisplayName, researchProjectTitle, resourceManagerDisplayName);

This could be a bit error prone if the template changes often, and someone's not being careful to make sure the numbering in the template matches the order of parameters being passed in. 如果模板经常更改,这可能会出现一些错误,并且有人不小心确保模板中的编号与传入参数的顺序匹配。

Option 1 - Using Run-Time Text Templates 选项1-使用运行时文本模板


As an elegant solution you can use Run-time Text Templates . 作为一种优雅的解决方案,您可以使用运行时文本模板 Add a new Item of Runtime Text Template to your project and and name the file ResearchRequestTemplate.tt put this content in it: 在您的项目中添加一个新的Runtime Text Template项目,并将其命名为ResearchRequestTemplate.tt文件,将其内容放入其中:

<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ parameter name="FellowDisplayName" type="System.String"#>
<#@ parameter name="ResearchProjectTitle" type="System.String"#>
<#@ parameter name="ResourceManagerDisplayName" type="System.String"#>
Hello <#= FellowDisplayName #>

You have requested access to the <#= ResearchProjectTitle #> Project.

    Please submit all paperwork and badge ID to <#= ResourceManagerDisplayName #>

Then use it this way: 然后以这种方式使用它:

var template = new ResearchRequestTemplate();
template.Session = new Dictionary<string, object>();
template.Session["FellowDisplayName"]= value1;
template.Session["ResearchProjectTitle"]= value2;
template.Session["ResourceManagerDisplayName"] = value3;
template.Initialize();
var result = template.TransformText();

This is a very flexible way and you can simply extend it, because visual studio generates a C# class for your template and for example you can create a partial class for it and put some properties in it and use typed properties simply. 这是一种非常灵活的方法,您可以简单地扩展它,因为Visual Studio会为您的模板生成一个C#类,例如,您可以为其创建一个部分类,并在其中放置一些属性,然后简单地使用类型化的属性。

Option 2 - Named String.Format 选项2-命名为String.Format


You can use named string format methods: 您可以使用命名字符串格式方法:

Here is an implementation by James Newton : 这是James Newton的实现

public static class Extensions
{
    public static string FormatWith(this string format, object source)
    {
      return FormatWith(format, null, source);
    }

    public static string FormatWith(this string format, IFormatProvider provider, object source)
    {
      if (format == null)
        throw new ArgumentNullException("format");

      Regex r = new Regex(@"(?<start>\{)+(?<property>[\w\.\[\]]+)(?<format>:[^}]+)?(?<end>\})+",
        RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);

      List<object> values = new List<object>();
      string rewrittenFormat = r.Replace(format, delegate(Match m)
      {
        Group startGroup = m.Groups["start"];
        Group propertyGroup = m.Groups["property"];
        Group formatGroup = m.Groups["format"];
        Group endGroup = m.Groups["end"];

        values.Add((propertyGroup.Value == "0")
          ? source
          : DataBinder.Eval(source, propertyGroup.Value));

        return new string('{', startGroup.Captures.Count) + (values.Count - 1) + formatGroup.Value
          + new string('}', endGroup.Captures.Count);
      });

      return string.Format(provider, rewrittenFormat, values.ToArray());
    }
}

And the usage: 以及用法:

"{CurrentTime} - {ProcessName}".FormatWith(
    new { CurrentTime = DateTime.Now, ProcessName = p.ProcessName });

You can also take a look at an implementation by Phil Haack . 您还可以查看Phil Haack的实现

You can use a simple replacement scheme using regular expressions: 您可以使用使用正则表达式的简单替换方案:

var replacements = new Dictionary<string, string>() {
    { "FellowDisplayName", "Mr Doe" },
    { "ResearchProjectTitle", "Frob the Baz" },
    { "ResourceManagerDisplayName", "Mrs Smith" },
};

string template = getTemplate();    
string result = Regex.Replace(template, "\\{\\s*(.*?)\\s*\\}", m => {
    string value;
    if (replacements.TryGetValue(m.Groups[1].Value, out value))
    {
        return value;
    }
    else
    {
        // TODO: What should happen if we don't know what the template value is?
        return string.Empty;
    }   
});
Console.WriteLine(result);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM