使用C#6中的命名参数进行字符串插值

Lee*_*ury 18 c# asp.net asp.net-mvc

鉴于我有一个存储在我的数据库中的元数据资源字符串将返回如下:

var pageTitle = "Shop the latest {category1} Designer {category2} {category3} at www.abc.com";
Run Code Online (Sandbox Code Playgroud)

我想替换{placeholders}变量values;

var category1 = "womenswear";
var category2 = "dresses";
var category3 = "cocktail dresses";
Run Code Online (Sandbox Code Playgroud)

我试过了,没有运气;

var newTitle = $"pageTitle, category1, category2, category3";
var newTitle = $(pageTitle, category1, category2, category3);
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用string.Replace()它有性能开销.有谁知道如何使用最新的C#字符串插值有效地完成这项工作?

Pat*_*man 19

你不能在这里使用字符串插值.字符串插值是一种编译时重写方法string.Format,这是您应该使用的解决方案:

var newTitle = string.Format("{0}, {1}, {2}, {3}", pageTitle, category1, category2, category3);
Run Code Online (Sandbox Code Playgroud)

或者string.Join:

var newTitle - string.Join(", ", new string[] { pageTitle, category1, category2, category3 });
Run Code Online (Sandbox Code Playgroud)

由于您是从数据库加载的,因此在您的情况下继续使用可能会更好string.Replace.


Cod*_*ter 18

我知道我可以使用具有性能开销的string.Replace()

仅仅纳秒.你不应该过早地优化.

如上所述,C#6字符串插值功能在编译时发生.如果要在运行时执行此操作,则必须使用字符串替换.

我假设你的字符串格式化,以便于编辑,没有固定的替换顺序,所以只需这样做:

var input = "Shop the latest {category1} Designer {category2} {category3} at www.abc.com";
var category1 = "womenswear";
var category2 = "dresses";
var category3 = "cocktail dresses";

var result = input.Replace("{category1}", category1)
                  .Replace("{category2}", category2)
                  .Replace("{category3}", category3);
Run Code Online (Sandbox Code Playgroud)

这将是有效的.您还可以将替换值存储在字典中,并循环键以使用值替换键.

  • Nitpick:如果`category1 =="{category2}"`这会产生意想不到的结果:)但我承认:我一直都在使用它. (5认同)

das*_*ght 8

虽然.NET没有为此提供内置功能,但您可以使用正则表达式轻松构建一个非常好的实现:

public static string Format(string formatWithNames, IDictionary<string,object> data) {
    int pos = 0;
    var args = new List<object>();
    var fmt = Regex.Replace(
        formatWithNames
    ,   @"(?<={)[^}]+(?=})"
    ,   new MatchEvaluator(m => {
            var res = (pos++).ToString();
            var tok = m.Groups[0].Value.Split(':');
            args.Add(data[tok[0]]);
            return tok.Length == 2 ? res+":"+tok[1] : res;
        })
    );
    return string.Format(fmt, args.ToArray());
}
Run Code Online (Sandbox Code Playgroud)

我们的想法是用连续数字替换名称(请参阅参考资料sb.Append(pos++)),构建一个对象参数数组(请参阅参考资料args.Add(data[tok[0]])),并将结果传递string.Format给使用string的格式化功能.

现在,您可以将资源Format与键值对字典一起传递给它,并获取使用.NET内置格式化功能格式化的字符串:

var x = new Dictionary<string,object> {
    {"brown", 1}
,   {"jumps", 21}
,   {"lazy", 42}
};
Console.WriteLine("{0}", Format("Quick {brown} fox {jumps:C} over the {lazy:P} dog", x));
Run Code Online (Sandbox Code Playgroud)

请注意,$字符串文字前面没有,所以这里没有C#的内置插值.

这打印

Quick 1 fox $21.00 over the 4,200.00 % dog
Run Code Online (Sandbox Code Playgroud)

该方法基于Scott Hanselman想法,除了格式化方式不同.

演示.


D S*_*ley 5

如果您不想使用字符串替换,则需要使用原始格式化语法:

var pageTitle = "Shop the latest {0} Designer {1} {2} at www.abc.com";

var category1 = "womenswear";
var category2 = "dresses";
var category3 = "cocktail dresses";

var newTitle = string.Format(pageTitle, category1, category2, category3);
Run Code Online (Sandbox Code Playgroud)

或把格式化字符串之后的变量:

var category1 = "womenswear";
var category2 = "dresses";
var category3 = "cocktail dresses";

var newTitle = $"Shop the latest {0} Designer {0} {0} at www.abc.com";
Run Code Online (Sandbox Code Playgroud)

字符串插值string.Format编译时转换为调用,因此无法在运行时使格式化字符串成为变量.