是否有一个"String.Format"可以接受命名输入参数而不是索引占位符?

Pol*_*ich 88 .net c# string string-formatting

这就是我所知道的

str = String.Format("Her name is {0} and she's {1} years old", "Lisa", "10");
Run Code Online (Sandbox Code Playgroud)

但我想要类似的东西

str = String("Her name is @name and she's @age years old");
str.addParameter(@name, "Lisa");
str.addParameter(@age, 10);
Run Code Online (Sandbox Code Playgroud)

Fab*_*NET 138

在C#6中,您可以使用字符串插值:

string name = "Lisa";
int age = 20;
string str = $"Her name is {name} and she's {age} years old";
Run Code Online (Sandbox Code Playgroud)

正如Doug Clutter评论中提到的,字符串插值也支持格式字符串.可以通过在冒号后指定格式来更改格式.以下示例将输出一个带逗号和2位小数的数字:

var str = $"Your account balance is {balance:N2}"
Run Code Online (Sandbox Code Playgroud)

正如Bas他的回答中提到的,字符串插值不支持模板字符串.实际上,它没有内置的支持.幸运的是,它存在于一些很棒的库中.


例如, SmartFormat.NET支持命名占位符:

Smart.Format("{Name} from {Address.City}, {Address.State}", user)

// The user object should at least be like that 

public class User
{
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string City { get; set; }
    public string State { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

它可以在NuGet上获得.


胡子也是一个很好的解决方案.Bas他的回答中很好地描述了它的优点.


Bas*_*Bas 30

如果您可以分配包含用于替换模板参数的数据的局部变量,则可以使用C#6.0 字符串插值功能.

基本原则是您可以根据输入数据执行相当高级的字符串替换逻辑.

简单的例子:

string name = "John";
string message = $"Hello, my name is {name}."
Run Code Online (Sandbox Code Playgroud)

复杂的例子:

List<string> strings = ...
string summary = $"There are {strings.Count} strings. " 
  + $"The average length is {strings.Select(s => s.Length).Average()}"
Run Code Online (Sandbox Code Playgroud)

缺点:

  • 不支持动态模板(例如,来自资源文件)

(主要)优点:

  • 它对您的模板替换强制执行编译时检查.

一个很好的开源解决方案,具有几乎相同的语法,是Mustache.它有两个可用的C#实现,我可以找到 - mustache-sharpNustache.

我曾经使用mustache-sharp并发现它没有与字符串插值相同的功能,但接近.例如,您可以执行以下操作(从它的github页面中窃取).

Hello, {{Customer.Name}}
{{#newline}}
{{#newline}}
{{#with Order}}
{{#if LineItems}}
Here is a summary of your previous order:
{{#newline}}
{{#newline}}
{{#each LineItems}}
    {{ProductName}}: {{UnitPrice:C}} x {{Quantity}}
    {{#newline}}
{{/each}}
{{#newline}}
Your total was {{Total:C}}.
{{#else}}
You do not have any recent purchases.
{{/if}}
{{/with}}
Run Code Online (Sandbox Code Playgroud)

  • 不支持动态模板?您的意思是我们无法从配置文件中加载字符串“This is {name} and he is {age} years old”,然后在代码中的某个位置进行插值,从而变量“name”和“age”可能可用但“看不见”,因为插值仅在编译时起作用?为什么不给一些插值方法字符串并传递所需的变量,如下所示:`string s =“This is {name} and he is {age} years old”; // 从文件名加载 = "Tini"; 年龄=21;string s2 = s.Interpolate(name,age);` 有这样的方法吗? (3认同)

Cha*_*ava 26

如果您的项目中没有C#6,则可以使用Linq的.Aggregate():

    var str = "Her name is @name and she's @age years old";

    var parameters = new Dictionary<string, object>();
    parameters.Add("@name", "Lisa");
    parameters.Add("@age", 10);

    str = parameters.Aggregate(str, (current, parameter)=> current.Replace(parameter.Key, parameter.Value.ToString()));
Run Code Online (Sandbox Code Playgroud)

如果你想要一些与问题中特定语法相匹配的东西,你可以将基于Aggregate的非常简单的类放在一起:

public class StringFormatter{

    public string Str {get;set;}

    public Dictionary<string, object> Parameters {get;set;}

    public StringFormatter(string p_str){
        Str = p_str;
        Parameters = new Dictionary<string, object>();
    }

    public void Add(string key, object val){
        Parameters.Add(key, val);
    }

    public override string ToString(){
        return Parameters.Aggregate(Str, (current, parameter)=> current.Replace(parameter.Key, parameter.Value.ToString()));
    }

}
Run Code Online (Sandbox Code Playgroud)

适用于:

var str = new StringFormatter("Her name is @name and she's @age years old");
str.Add("@name", "Lisa");
str.Add("@age", 10);

Console.WriteLine(str);
Run Code Online (Sandbox Code Playgroud)

请注意,这是一个外观简洁的代码,旨在易于理解性能.

  • 这是被低估的。这既授你鱼,又教你钓鱼。 (4认同)
  • 我同意这个答案太棒了! (2认同)

Ste*_*eve 19

使用C#6,您可以使用String Interpolation直接将变量添加到字符串中.

例如:

string name = "List";
int age = 10;

var str = $"Her name is {name} and she's {age} years old";
Run Code Online (Sandbox Code Playgroud)

注意,在$字符串格式之前使用美元符号().

  • 我认为String.Format调用在这里没用,因为你正在使用字符串插值. (3认同)

Art*_*tem 14

那么为什么不只是替换?

string str = "Her name is @name and she's @age years old";
str = str.Replace("@name", "Lisa");
str = str.Replace("@age", "10");
Run Code Online (Sandbox Code Playgroud)


Zoh*_*led 7

没有内置的方法可以做到这一点,但你可以编写一个类来为你做这个.
这样的事情可以让你开始:

public class ParameterizedString
{
    private string _BaseString;
    private Dictionary<string, string> _Parameters;

    public ParameterizedString(string baseString)
    {
        _BaseString = baseString;
        _Parameters = new Dictionary<string, string>();
    }

    public bool AddParameter(string name, string value)
    {
        if(_Parameters.ContainsKey(name))
        {
            return false;
        }
        _Parameters.Add(name, value);
        return true;
    }

    public override string ToString()
    {
        var sb = new StringBuilder(_BaseString);
        foreach (var key in _Parameters.Keys)
        {
            sb.Replace(key, _Parameters[key]);
        }
        return sb.ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,此示例不强制任何参数名称约定.这意味着您应该非常小心地选择参数名称,否则您可能最终会替换您不想要的部分字符串.


ehh*_*ehh 5

字符串插值是一个很好的解决方案,但它需要C#6.

在这种情况下,我使用StringBuilder

var sb = new StringBuilder();

sb.AppendFormat("Her name is {0} ", "Lisa");
sb.AppendFormat("and she's {0} years old", "10");
// You can add more lines

string result = sb.ToString();
Run Code Online (Sandbox Code Playgroud)