C#中的带有变量内容的字符串插值

17

可以将字符串的模板存储在变量中并对其进行插值吗?

var name = "Joe";
var template = "Hi {name}";

然后我想做类似这样的事情:

var result = $template;

原因是我的模板将来自数据库。


3
不太清楚您的问题。您能澄清一下从数据库中获取了哪些值以及您期望的输出是什么吗? - Selman Genç
5个回答

13

我猜这些字符串的参数数量始终相同,即使它们可能会更改。例如,今天template"Hi {name}",而明天可能是"Hello {name}"

简短的回答:不能按照你提出的方式实现。

备选方案1:使用string.Format方法。

您可以在数据库中存储类似以下内容:

"Hi {0}"

然后,当你从数据库中检索字符串模板时,你可以编写:

var template = "Hi {0}"; //retrieved from db
var name = "Joe";
var result = string.Format(template, name);
//now result is "Hi Joe"

带有 2 个参数:

var name2a = "Mike";
var name2b = "John";
var template2 = "Hi {0} and {1}!"; //retrieved from db
var result2 = string.Format(template2, name2a, name2b);
//now result2 is "Hi Mike and John!"

替代方案2:使用占位符。

您可以在数据库中存储类似以下内容的数据:

"Hi {name}"

然后,当您从数据库中检索字符串模板时,可以编写:

var template = "Hi {name}"; //retrieved from db
var name = "Joe";
var result = template.Replace("{name}", name);
//now result is "Hi Joe"

有3个参数:

var name2a = "Mike";
var name2b = "John";
var template2 = "Hi {name2a} and {name2b}!"; //retrieved from db
var result2 = template2
    .Replace("{name2a}", name2a)
    .Replace("{name2b}", name2b);
//now result2 is "Hi Mike and John!"

请注意选择用于占位符的标记。在这里,我使用了大括号 {}。您应该找到一些不太可能与您的其余文本发生冲突的内容。这完全取决于您的上下文。


谢谢你的回答。我已经使用string.Format很多年了,但是字符串插值使代码更易读。我希望它可以与模板变量一起使用,因为当你有超过20个变量时,string.Format会变得非常丑陋和容易出错。我可能会选择使用string.Replace替换每个变量,并自己替换模板占位符。 - Tony Lugg
@TonyLugg 使用string.Replace相比使用string.Format有什么优势?你会如何使用它,我对此很好奇。 - Massimiliano Kraus
抱歉回复晚了。我有很多需要在一个非常大的文档中替换的变量。使用string.Format会非常难以阅读和容易出错(顺序必须与源字符串中的{#}实例匹配)。使用自解释的方式替换哪个变量被哪个替换字符串所替换。 - Tony Lugg

10
可以按照要求使用动态编译来完成,例如通过Microsoft.CodeAnalysis.CSharp.Scripting包。例如:
var name = "Joe";
var template = "Hi {name}";
var result = await CSharpScript.EvaluateAsync<string>(
    "var name = \"" + name + "\"; " +
    "return $\"" + template + "\";");

请注意,这种方法速度较慢,您需要添加更多的逻辑来处理字符串中引号(和注入攻击)的转义,但上述内容可以作为概念验证。


超级黑客但合法,我喜欢它 ;) - Brady Moritz
请注意将您项目中使用的 .NET 版本与此新编译器包的版本相匹配。请参见此处: https://github.com/dotnet/roslyn/wiki/NuGet-packages - Newclique
哦,还有一个后续问题:在使用这种方法时,是否需要采取任何措施使您的代码线程安全? - Newclique
1
@Wade:EvaluateAsync方法接收一个不可变字符串作为参数,因此对于原始变量的任何后续更改都是不受影响的。该代码是线程安全的。 - Douglas

2
我在我的应用程序中也有同样的需求,所以我将分享我的解决方案,使用 String.Replace()。如果您能够使用 LINQ,则可以使用Aggregate方法(它是一个减少函数,如果您熟悉函数式编程),结合提供所需替换的字典。
string template = "Hi, {name} {surname}";

Dictionary<string, string> substitutions = new Dictionary<string, string>() {
    { "name", "Joe" },
    { "surname", "Bloggs" },
};

string result = substitutions.Aggregate(template, (args, pair) =>
    args.Replace($"{{{pair.Key}}}", pair.Value)
);
// result == "Hi, Joe Bloggs"

这是通过从模板开始,然后迭代替换字典中的每个项目,替换每个出现的内容来实现的。一个Replace()调用的结果被馈送到下一个输入中,直到所有替换都完成。 {{{pair.Key}}}部分只是为了转义用于查找占位符的{}

我喜欢这个解决方案。它可以轻松添加额外的占位符,并避免循环。 - dougczar

2

不行,因为这需要在字符串创建时(编译时)具有name值。考虑使用String.FormatString.Replace


https://weblogs.asp.net/bleroy/c-6-string-interpolation-is-not-a-templating-engine-and-it-s-not-the-new-string-format - user1529413

1
这段话的大意是:这已经很旧了,但我刚刚发现它对我来说是新的!虽然它可能有点过头了,但我已经用Handlebars.NET做了这样的事情。你可以创建相当复杂的模板,并合并分层数据结构作为上下文。有循环和条件部分的规则,部分模板组合甚至辅助函数扩展点。它还优雅地处理许多数据类型。在这里无法详细介绍,但以下是一个简短的示例说明...
    var source = @"Hello {{Guest.FirstName}}{{#if Guest.Surname}} {{Guest.Surname}}{{/if}}!";
    var template = Handlebars.Compile(source);

    var rec = new {
        Guest = new { FirstName = "Bob", Surname = null }
    };

    var resultString = template(rec);

在这种情况下,如果值不为 null 或空,则姓氏将仅包括在输出中。
现在可以承认,相对于简单的字符串插值,这对用户来说更加复杂,但请记住,如果您愿意,仍然可以使用 {{fieldName}},只是您也可以做更多的事情。
这个特定的 nuGet 是 HandlebarsJs 的一个移植版本,因此具有高度的兼容性。HandlebarsJs 本身是 Mustache 的一个移植版本 - 虽然 Mustache 有直接的 dotNet 移植版本,但我认为 HandlebarsNET 更好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接