web-dev-qa-db-ja.com

インデックスプレースホルダーの代わりに名前付き入力パラメーターを受け入れることができる「String.Format」はありますか?

これは私が知っていることです

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

しかし、私は次のようなものが欲しい

str = String("Her name is @name and she's @age years old");
str.addParameter(@name, "Lisa");
str.addParameter(@age, 10);
86

C#6では、 文字列補間 を使用できます。

string name = "Lisa";
int age = 20;
string str = $"Her name is {name} and she's {age} years old";

Doug Clutterhis comment で述べたように、文字列補間は format string もサポートします。コロンの後に指定することにより、形式を変更することができます。次の例では、カンマと小数点以下2桁の数値を出力します。

var str = $"Your account balance is {balance:N2}"

Bashis answer で述べたように、文字列補間はテンプレート文字列をサポートしていません。実際、そのためのサポートは組み込まれていません。幸いなことに、いくつかの素晴らしいライブラリに存在します。


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

NuGet で利用できます。


Mustache も素晴らしい解決策です。 Bashis answer で長所を説明しています。

136

テンプレートパラメータの置換に使用するデータを含むローカル変数を割り当てても問題ない場合は、C#6.0 文字列補間機能 を使用できます。

基本原則は、入力データに基づいてかなり高度な文字列置換ロジックを実行できることです。

簡単な例:

string name = "John";
string message = $"Hello, my name is {name}."

複雑な例:

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

欠点:

  • 動的テンプレートのサポートなし(例:リソースファイルから)

(主な)利点:

  • テンプレートの置換時にコンパイル時チェックを強制します。

ほとんど同じ構文を持つニースのオープンソースソリューションは、 Mustache です。私が見つけることができたものから2つの利用可能な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}}
29
Bas

プロジェクトで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()));

質問の特定の構文に一致するものが必要な場合は、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()));
    }

}

次のように使用可能:

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

これは見栄えの良いコードであり、パフォーマンスを理解しやすいように調整されていることに注意してください。

25
Chakrava

C#6では、 String Interpolation を使用して変数を文字列に直接追加できます。

例えば:

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

var str = $"Her name is {name} and she's {age} years old";

文字列形式の前にドル記号($)を使用していることに注意してください。

18
Steve

では、なぜ単に置き換えないのですか?

string str = "Her name is @name and she's @age years old";
str = str.Replace("@name", "Lisa");
str = str.Replace("@age", "10");
14
Artem

これを行うための組み込みの方法はありませんが、あなたのためにそれを行うクラスを書くことができます。
次のような何かがあなたを始めることができます:

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

この例では、パラメーター名の規則は強制されません。これは、パラメータ名を非常に慎重に選択する必要があることを意味します。そうしないと、意図しない文字列の一部を置き換えてしまう可能性があります。

7
Zohar Peled

文字列補間は良い解決策ですが、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();
5
ehh

C#6の文字列補間で式を使用することもできます。

string name = "Lisa";
int age = 20;
string str = $"Her name is {name} and she's {age} year{(age == 1 ? "" : "s")} old";
3
Sean McLarty
    string name = "Lisa";
    int age = 20;
    string str = $"Her name is {name} and she's {age} years old";

これは Interpolated String と呼ばれ、基本的にはその中に式を含むテンプレート文字列です。

2
Matt.Mull