C#中将字符串变量转换为FormattableString的实现方案
Got it, let's break this down. Since your formatted string is coming from app.config (a runtime value), we can't rely on the compiler's built-in string interpolation to create a FormattableString directly. Instead, we'll use FormattableStringFactory to manually construct one after adjusting the placeholder syntax.
Option 1: Manual Placeholder Mapping (Best for Small, Fixed Variables)
If you only have a couple of variables like greeting and name, this straightforward approach works great:
private void doStuff() { var toBeFormatted = ConfigurationManager.AppSettings["FormattedString"]; string greeting = @"Hi There"; string name = @"Bob"; // Replace named placeholders with index-based ones (required for FormattableStringFactory) var indexedFormat = toBeFormatted.Replace("{greeting}", "{0}").Replace("{name}", "{1}"); // Create the FormattableString instance FormattableString formattedString = FormattableStringFactory.Create(indexedFormat, greeting, name); // Use the FormattableString as needed string finalResult = formattedString.ToString(); // Outputs "Hi There, Bob." // Or use it for culture-specific formatting (a key benefit of FormattableString) string frenchResult = formattedString.ToString(CultureInfo.GetCultureInfo("fr-FR")); }
Why this works:
FormattableStringFactory.Create() takes an index-based format string (like what string.Format uses) and an array of parameters, then returns a valid FormattableString object. This preserves all the features of FormattableString, like support for culture-aware formatting.
Option 2: Automatic Placeholder Mapping (Better for Dynamic/More Variables)
If you might add more variables later or don't want to manually update placeholder replacements, use reflection and regex to map placeholder names to your variables automatically:
using System.Reflection; using System.Text.RegularExpressions; using System.Globalization; private void doStuff() { var toBeFormatted = ConfigurationManager.AppSettings["FormattedString"]; string greeting = @"Hi There"; string name = @"Bob"; // Map variable names to their values (use nameof() to avoid typos) var variableMap = new Dictionary<string, object> { { nameof(greeting), greeting }, { nameof(name), name } }; // Extract all unique named placeholders from the config string var placeholders = Regex.Matches(toBeFormatted, @"\{(\w+)\}") .Cast<Match>() .Select(match => match.Groups[1].Value) .Distinct() .ToList(); // Convert named placeholders to index-based ones and build the parameter list string indexedFormat = toBeFormatted; var parameters = new List<object>(); for (int i = 0; i < placeholders.Count; i++) { string placeholderName = placeholders[i]; indexedFormat = indexedFormat.Replace($"{{{placeholderName}}}", $"{{{i}}}"); parameters.Add(variableMap[placeholderName]); } // Create the FormattableString FormattableString formattedString = FormattableStringFactory.Create(indexedFormat, parameters.ToArray()); // Use the result string finalResult = formattedString.ToString(); }
How this works:
- We use regex to pull all named placeholders (like
greetingandname) from the config string. - We replace each named placeholder with an index-based one (
{0},{1}, etc.). - We collect the corresponding variable values and pass everything to
FormattableStringFactory.Create()to build our object.
This way, if you add a new placeholder to app.config (like {time}) and a matching variable in your code, you just need to add it to the variableMap—no need to update the replacement logic.
内容的提问来源于stack exchange,提问作者John Bustos

