首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >C#6.0字符串插值本地化

C#6.0字符串插值本地化
EN

Stack Overflow用户
提问于 2015-03-16 09:07:45
回答 4查看 15.8K关注 0票数 68

C#6.0有一个string interpolation --一个很好的格式化字符串的特性,比如:

代码语言:javascript
复制
 var name = "John";
 WriteLine($"My name is {name}");

该示例将转换为

代码语言:javascript
复制
 var name = "John";
 WriteLine(String.Format("My name is {0}", name));

从本地化的角度来看,最好像这样存储字符串:

代码语言:javascript
复制
"My name is {name} {middlename} {surname}" 

而不是使用String.Format表示法:

代码语言:javascript
复制
"My name is {0} {1} {2}"

如何使用字符串插值进行.NET本地化?有没有办法把$"...“到资源文件?或者字符串应该像"...{name}“那样存储并以某种方式即时插入?

附注:这个问题不是关于“如何做string.FormatIt扩展”(有很多这样的库,所以答案,等等)。这个问题是关于“本地化”上下文中的“字符串插值”的罗斯林扩展(两者都是MS .NET词汇表中的术语),或者像迪伦提出的动态用法。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2018-04-09 13:20:01

使用Microsoft.CodeAnalysis.CSharp.Scripting包可以实现这一点。

您将需要创建一个对象来存储数据,下面使用的是动态对象。您还可以创建一个具有所有必需属性的特定类。在描述的here中将动态对象包装在类中的原因。

代码语言:javascript
复制
public class DynamicData
{
    public dynamic Data { get; } = new ExpandoObject();
}

然后,您可以使用它,如下所示。

代码语言:javascript
复制
var options = ScriptOptions.Default
    .AddReferences(
        typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).GetTypeInfo().Assembly,
        typeof(System.Runtime.CompilerServices.DynamicAttribute).GetTypeInfo().Assembly);

var globals = new DynamicData();
globals.Data.Name = "John";
globals.Data.MiddleName = "James";
globals.Data.Surname = "Jamison";

var text = "My name is {Data.Name} {Data.MiddleName} {Data.Surname}";
var result = await CSharpScript.EvaluateAsync<string>($"$\"{text}\"", options, globals);

这是编译并执行代码片段,因此这是真正的C#字符串插值。尽管你必须考虑它的性能,因为它实际上是在运行时编译和执行你的代码。如果您可以使用CSharpScript.Create编译和缓存代码,则可以避免这种性能影响。

票数 3
EN

Stack Overflow用户

发布于 2015-03-16 10:12:19

插值字符串将花括号之间的块计算为C#表达式(例如{expression}{1 + 1}{person.FirstName})。

这意味着插值字符串中的表达式必须引用当前上下文中的名称。

例如,以下语句将不会编译:

代码语言:javascript
复制
var nameFormat = $"My name is {name}"; // Cannot use *name*
                                       // before it is declared
var name = "Fred";
WriteLine(nameFormat);

类似地:

代码语言:javascript
复制
class Program
{
    const string interpolated = $"{firstName}"; // Name *firstName* does not exist
                                                // in the current context
    static void Main(string[] args)
    {
        var firstName = "fred";
        Console.WriteLine(interpolated);
        Console.ReadKey();
    }
}

回答你的问题:

框架当前没有提供在运行时评估内插字符串的机制。因此,您不能在开箱即用时存储字符串和插值。

有一些库可以处理字符串的运行时插值。

票数 35
EN

Stack Overflow用户

发布于 2016-09-19 17:09:18

正如在前面的回答中所说的:您目前不能在运行时(例如从资源文件)加载用于字符串插值的格式字符串,因为它是在编译时使用的。

如果你不关心编译时特性,只想拥有命名的占位符,你可以使用如下的扩展方法:

代码语言:javascript
复制
public static string StringFormat(this string input, Dictionary<string, object> elements)
{
    int i = 0;
    var values = new object[elements.Count];
    foreach (var elem in elements)
    {
        input = Regex.Replace(input, "{" + Regex.Escape(elem.Key) + "(?<format>[^}]+)?}", "{" + i + "${format}}");
        values[i++] = elem.Value;
    }
    return string.Format(input, values);
}

请注意,这里不能有像{i+1}这样的内联表达式,并且这不是具有最佳性能的代码。

您可以将其与从资源文件加载的字典一起使用,或者像这样内联:

代码语言:javascript
复制
var txt = "Hello {name} on {day:yyyy-MM-dd}!".StringFormat(new Dictionary<string, object>
            {
                ["name"] = "Joe",
                ["day"] = DateTime.Now,
            });
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29068194

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档