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

问题描述 投票:0回答:4

我们有一堆文本模板,它们是我们的 Visual Studio 解决方案中嵌入的资源。

我正在使用像这样的简单方法来加载它们:

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

所以我可以使用上述方法加载文件,但是如何用我在代码中创建的变量替换文件内的模板变量?这可能吗?也许我的想法都是错的......

ResearchRequestTemplate.txt:

Hello { FellowDisplayName }

You have requested access to the { ResearchProjectTitle } Project.

    Please submit all paperwork and badge ID to { ResourceManagerDisplayName }

谢谢!

c# .net c#-4.0
4个回答
4
投票

您可以使用一系列

string.Replace()
语句。

或者您可以修改模板并使用

string.Format
:

Hello {0}

You have requested access to the {1} Project.

    Please submit all paperwork and badge ID to {2}

读入模板后,插入正确的值:

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

如果模板经常更改,并且有人不小心确保模板中的编号与传入参数的顺序匹配,这可能会有点容易出错。


3
投票

选项 1 - 使用运行时文本模板


作为一个优雅的解决方案,您可以使用运行时文本模板。在您的项目中添加一个新的运行时文本模板项,并将该文件命名为

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 #>

然后这样使用:

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

这是一种非常灵活的方式,您可以简单地扩展它,因为 Visual Studio 会为您的模板生成一个 C# 类,例如,您可以为其创建一个部分类并在其中放入一些属性并简单地使用类型化属性。

选项 2 - 命名 String.Format


您可以使用命名字符串格式方法:

这是 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());
    }
}

用法:

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

您还可以查看 Phil Haack 的实现


1
投票

您可以使用正则表达式来使用简单的替换方案:

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

0
投票

这个答案提供了一个具有命名参数的选项:

Format("test {first} and {another}", new { first = "something", another = "something else" })
...
public string Format(string input, object p)
{
    foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(p))
    {
        input = input.Replace("{" + prop.Name + "}", (prop.GetValue(p) ?? "(null)").ToString());
    }
    return input;
}
© www.soinside.com 2019 - 2024. All rights reserved.