String Interpolation With Variable Content in C#

Can one store the template of a string in a variable and use interpolation on it?

var name = "Joe";
var template = "Hi {name}";

I then want to do something like:

var result = $template;

The reason is my templates will come from a database.


Solution 1:

I guess that these strings will have always the same number of parameters, even if they can change. For example, today template is "Hi {name}", and tomorrow could be "Hello {name}".

Short answer: No, you cannot do what you have proposed.

Alternative 1: use the string.Format method.

You can store in your database something like this:

"Hi {0}"

Then, when you retrieve the string template from the db, you can write:

var template = "Hi {0}"; //retrieved from db
var name = "Joe";
var result = string.Format(template, name);
//now result is "Hi Joe"

With 2 parameters:

var name2a = "Mike";
var name2b = "John";
var template2 = "Hi {0} and {1}!"; //retrieved from db
var result2 = string.Format(template2, name2a, name2b);
//now result2 is "Hi Mike and John!"

Alternative 2: use a placeholder.

You can store in your database something like this:

"Hi {name}"

Then, when you retrieve the string template from the db, you can write:

var template = "Hi {name}"; //retrieved from db
var name = "Joe";
var result = template.Replace("{name}", name);
//now result is "Hi Joe"

With 3 parameters:

var name2a = "Mike";
var name2b = "John";
var template2 = "Hi {name2a} and {name2b}!"; //retrieved from db
var result2 = template2
    .Replace("{name2a}", name2a)
    .Replace("{name2b}", name2b);
//now result2 is "Hi Mike and John!"

Pay attention at which token you choose for your placeholders. Here I used surrounding curly brackets {}. You should find something that is unlikely to cause collisions with the rest of your text. And that depends entirely on your context.

Solution 2:

This can be done as requested using dynamic compilation, such as through the Microsoft.CodeAnalysis.CSharp.Scripting package. For example:

var name = "Joe";
var template = "Hi {name}";
var result = await CSharpScript.EvaluateAsync<string>(
    "var name = \"" + name + "\"; " +
    "return $\"" + template + "\";");

Note that this approach is slow, and you'd need to add more logic to handle escaping of quotes (and injection attacks) within strings, but the above serves as a proof-of-concept.

Solution 3:

No you can't do that since it needs name value at the time string is created (compile time). Consider using String.Format or String.Replace instead.

Solution 4:

I just had the same need in my app so will share my solution using String.Replace(). If you're able to use LINQ then you can use the Aggregate method (which is a reducing function, if you're familiar with functional programming) combined with a Dictionary that provides the substitutions you want.

string template = "Hi, {name} {surname}";

Dictionary<string, string> substitutions = new Dictionary<string, string>() {
    { "name", "Joe" },
    { "surname", "Bloggs" },
};

string result = substitutions.Aggregate(template, (args, pair) =>
    args.Replace($"{{{pair.Key}}}", pair.Value)
);
// result == "Hi, Joe Bloggs"

This works by starting with the template and then iterating over each item in the substitution dictionary, replacing the occurrences of each one. The result of one Replace() call is fed into the input to the next, until all substitutions are performed.

The {{{pair.Key}}} bit is just to escape the { and } used to find a placeholder.