c# - dynamic string interpolation [duplicate]

2020-06-22 15:34发布

问题:

I'm trying to format some string dynamically with available variables in a specific context/scope.

This strings would have parts with things like {{parameter1}}, {{parameter2}} and these variables would exist in the scope where I'll try to reformat the string. The variable names should match.

I looked for something like a dynamically string interpolation approach, or how to use FormattableStringFactory, but I found nothing that really gives me what I need.

var parameter1 = DateTime.Now.ToString();
var parameter2 = "Hello world!";
var retrievedString = "{{parameter2}} Today we're {{parameter1}}";
var result = MagicMethod(retrievedString, parameter1, parameter2);
// or, var result = MagicMethod(retrievedString, new { parameter1, parameter2 });

Is there an existing solution or should I (in MagicMethod) replace these parts in the retrievedString with matching members of the anonymous object given as parameter (using reflection or something like that)?

EDIT:

Finally, I created an extension method to handle this:

internal static string SpecialFormat(this string input, object parameters) {
  var type = parameters.GetType();
  System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex( "\\{(.*?)\\}" );
  var sb = new System.Text.StringBuilder();
  var pos = 0;

  foreach (System.Text.RegularExpressions.Match toReplace in regex.Matches( input )) {
    var capture = toReplace.Groups[ 0 ];
    var paramName = toReplace.Groups[ toReplace.Groups.Count - 1 ].Value;
    var property = type.GetProperty( paramName );
    if (property == null) continue;
    sb.Append( input.Substring( pos, capture.Index - pos) );
    sb.Append( property.GetValue( parameters, null ) );
    pos = capture.Index + capture.Length;
  }

  if (input.Length > pos + 1) sb.Append( input.Substring( pos ) );

  return sb.ToString();
}

and I call it like this:

var parameter1 = DateTime.Now.ToString();
var parameter2 = "Hello world!";
var retrievedString = "{parameter2} Today we're {parameter1}";
var result = retrievedString.SpecialFormat( new { parameter1, parameter2 } );

Now, I don't use double braces anymore.

回答1:

You can use reflection coupled with an anonymous type to do this:

public string StringFormat(string input, object parameters)
{
    var properties = parameters.GetType().GetProperties();
    var result = input;

    foreach (var property in properties)
    {
        result = result.Replace(
            $"{{{{{property.Name}}}}}", //This is assuming your param names are in format "{{abc}}"
            property.GetValue(parameters).ToString());
    }

    return result;
}

And call it like this:

var result = StringFormat(retrievedString, new { parameter1, parameter2 });


回答2:

While not understanding what is the dificulty you're having, I'm placing my bet on

Replace( string oldValue, string newValue )

You can replace your "tags" with data you want.

var parameter1 = DateTime.Now.ToString();
var parameter2 = "Hello world!";
var retrievedString = "{{parameter2}} Today we're {{parameter1}}";
var result = retrievedString.Replace("{{parameter2}}", parameter2).Replace({{parameter1}}, parameter1);

EDIT

Author mentioned that he's looking at something that will take parameters and iterate the list. It can be done by something like

public static void Main(string[] args)
    {
        //your "unmodified" srting
        string text = "{{parameter2}} Today we're {{parameter1}}";

        //key = tag(explicitly) value = new string
        Dictionary<string, string> tagToStringDict = new Dictionary<string,string>();

        //add tags and it's respective replacement
        tagToStringDict.Add("{{parameter1}}", "Foo");
        tagToStringDict.Add("{{parameter2}}", "Bar");

        //this returns your "modified string"
        changeTagWithText(text, tagToStringDict);
    }

    public static string changeTagWithText(string text, Dictionary<string, string> dict)
    {
        foreach (KeyValuePair<string, string> entry in dict)
        {
            //key is the tag ; value is the replacement
            text = text.Replace(entry.Key, entry.Value);
        }
        return text;
    }

The function changeTagWithText will return:

"Bar Today we're Foo"

Using this method you can add all the tags to the Dictionary and it'll replace all automatically.



回答3:

If you know order of parameters, you can use string.Format() method (msdn). Then, your code will look like:

var parameter1 = DateTime.Now.ToString();
var parameter2 = "Hello world!";
var retrievedString = "{{0}} Today we're {{1}}";
var result = string.Format(retrievedString, parameter2, parameter1);