127

This is what I know

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

But I want something like

str = String("Her name is @name and she's @age years old");
str.addParameter(@name, "Lisa");
str.addParameter(@age, 10);
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Polamin Singhasuwich
  • 1,646
  • 2
  • 11
  • 20
  • 4
    Why you require such format? whats wrong with `.Format` – sujith karivelil Apr 21 '16 at 04:33
  • 2
    There is no "standard" way, but there are many approaches - eg. http://stackoverflow.com/questions/159017/named-string-formatting-in-c-sharp , http://stackoverflow.com/questions/20278554/replace-x-tokens-in-strings?lq=1 Also, consider a library like StringTemplate (or whatnot) if this is more than a simple one-off case. – user2864740 Apr 21 '16 at 04:35
  • 4
    @un-lucky I'm formatting a very long string and when I have to edit it it's very hard – Polamin Singhasuwich Apr 21 '16 at 04:38
  • 9
    You can use `var name = "Lisa"; var age = 10; var str = $"Her name is {name} and she's {age} years old;"` in C#6 – Rob Apr 21 '16 at 04:38
  • Why would you need that? What is the advantage of named parameters over index placeholders? – Zohar Peled Apr 21 '16 at 04:53
  • 3
    @ZoharPeled readability is one advantage, if you have many parameters it becomes hard to track what goes where. – Bas Apr 21 '16 at 04:54
  • 1
    @Bas that's where c#6's string interpolation comes in for the rescue (along with it's other advantages... I really don't see how using a named parameter solution that will force longer and probably less efficient code would have an advantage over an interpolated string. – Zohar Peled Apr 21 '16 at 04:57
  • @ZohadPeled The interpolated string has to be there at compile time - sometimes this is not possible (e.g. when you are reading strings from resources or a database). – Bas Apr 21 '16 at 05:05
  • 1
    Even before C#6, you could always just use `+` to concatenate strings, e.g.: `var name = "Lisa"; var age = 10; var str = "Her name is " + name + " and she's " + age + " years old";` It's not as pretty as the new interpolation feature, but it basically does the same thing. – Darrel Hoffman Apr 21 '16 at 14:39
  • 2
    This becomes an important issue when you translate the string into a different language! Then the order of the placeholders might be reversed. If you want to internationalize your application, such a string formatting scheme gives the translator more freedom. – Martin Ueding Apr 21 '16 at 15:01
  • A lot of the suggestions for string interpolation, which is ideal for compile-time situations. However, if you're loading the string from a file or other data source, interpolation is not a good choice. – Steve Guidi Aug 26 '20 at 17:22

9 Answers9

175

In C# 6 you can use string interpolation:

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

As Doug Clutter mentioned in his comment, string interpolation also supports format string. It's possible to change the format by specifying it after a colon. The following example will output a number with a comma and 2 decimal places:

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

As Bas mentioned in his answer, string interpolation doesn't support template string. Actually, it has no built in support for that. Fortunately it exists in some great libraries.


SmartFormat.NET for example has support for named placeholders:

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

It is available on NuGet and has excellent documentation.


Mustache is also a great solution. Bas has described its pros well in his answer.

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Fabien ESCOFFIER
  • 4,751
  • 1
  • 20
  • 32
  • so no way to make format string as a variable in the interpolation? aka `double d = 6.0; string format = "F2"; string interpolation = $"{d:format}";` – yalov Sep 01 '19 at 16:35
  • 1
    This answer is not about string formatting but string interpolation which is something different. The OP asked about string formatting. Think of a resource string with (preferably named) placeholders that goes into String.Format (or just using the $ sign) and then replace the placeholders with const or var values. – Youp Bernoulli Nov 11 '21 at 09:05
57

If you don't have C#6 available in your project you can use Linq's .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()));

If you want something matching the specific syntax in the question you can put together a pretty simple class based on 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()));
    }

}

Usable like:

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

Note that this is clean-looking code that's geared to being easy-to-understand over performance.

Chakrava
  • 823
  • 7
  • 10
34

If you are ok assigning a local variable that contains the data you use to replace the template parameters, you can use the C# 6.0 string interpolation feature.

The basic principle is that you can do fairly advanced string replacement logic based on input data.

Simple example:

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

Complex example:

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

Drawbacks:

  • No support for dynamic templates (e.g. from a resources file)

(Major) advantages:

  • It enforces compile time checks on your template replacement.

A nice open source solution that has almost the same syntax, is Mustache. It has two available C# implementations from what I could find - mustache-sharp and Nustache.

I have worked with mustache-sharp and found that it does not have the same power as the string interpolation, but comes close. E.g. you can do the following (stolen from it's github page).

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}}
Bas
  • 26,772
  • 8
  • 53
  • 86
  • 3
    No support for dynamic templates? Do you mean that we cannot load a string "This is {name} and he is {age} years old" let's say from a config file and then do the interpolation somewhere in the code, whereby the variables 'name' and 'age' might be available but "unseen" because interpolation works only at compile time? Why not give some interpolation method the string and pass by the needed variables like this: `string s = "This is {name} and he is {age} years old"; // loaded from file name = "Tini"; age = 21; string s2 = s.Interpolate(name,age);` Is there such method available? – brighty Jul 16 '19 at 14:52
  • That would be nice. I'd like to know too. Sounds like it's only possible with a third-party library. In my situation I'd like to have the template be a constant - what you have as "string s". – KevinVictor Mar 16 '21 at 14:25
  • As today, [mustache](https://mustache.github.io/) refer to [Stubble](https://github.com/StubbleOrg/Stubble) as the official C# implementation. – Maxime Gélinas Nov 04 '21 at 15:54
18

With C# 6 you can use String Interpolation to directly add variables into a string.

For example:

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

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

Note, the use of the dollar sign ($) before the string format.

Steve
  • 9,335
  • 10
  • 49
  • 81
17

So why not just Replace?

string str = "Her name is @name and she's @age years old";
str = str.Replace("@name", "Lisa");
str = str.Replace("@age", "10");
Artem
  • 1,535
  • 10
  • 13
  • 1
    this will generate as many additional strings as you have variables, which may not be desired – jk. Apr 21 '16 at 16:36
  • 1
    Why not? Perhaps many reasons. It takes three lines instead of one. If `@name` contains `@age` it will be interpolated, but not vice versa. It is inefficient, scanning the string once for every variable. `@` can't be escaped with, say, `\@` or `@@`. – John Kugelman Apr 21 '16 at 17:57
8

There is no built in way to do this, but you can write a class that will do it for you.
Something like this can get you started:

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

Note that this example does not force any parameter name convention. This means that you should be very careful picking your parameters names otherwise you might end up replacing parts of the string you didn't intend to.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
6

string interpolation is a good solution however it requires C#6.

In such case I am using 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();
ehh
  • 3,412
  • 7
  • 43
  • 91
2

You can also use expressions with C#6's string interpolation:

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

This is called an Interpolated String, which is a basically a template string that contains expressions inside of it.

Matt.Mull
  • 44
  • 4