Search code examples
c#stringformattinginterpolationtemplating

Dynamic String Templating in C#


I'm looking for a way to perform string interpolation, but where the template string is in a variable ahead of time, rather than using true string interpretation where the $"{a}{b}" is immediately parameterized and returned.

There are tons of places this would be useful, but as the clearest example, I'm writing an ETL (Extract Transform Load) pipeline which has dozens of different REST APIs I need to hit. The same two arguments occur in the different URIs repeatedly, and I'd like to dynamically replace them with user provided values. Two such examples are listed below.

  • http://www.example.com/projects/{projectId}/data
    • E.g., given projectId of 1, I would expect http://www.example.com/projects/1/data
  • http://www.example.com/project/{projectId}/data?uploadId={uploadId}

This can be easily accomplished using string interpolation if I have the values available at run time, e.g."

int projectId = 1;
int uploadId = 3;
string uri = $"http://www.example.com/project/{projectId}/data?uploadId={uploadId}";
/* evaluates to "http://www.example.com/project/1/data?uploadId=1" */

However I want to build up these parameterized strings ahead of time, and be able to replace them with whatever variables I have available in that context. In otherwords, in pseudocode:

int projectId = 1;
int uploadId = 3;
string uriTemplate = "http://www.example.com/project/{projectId}/data?uploadId={uploadId}";
string uri = ReplaceNameTags(uriTemplate, projectId, uploadId)
// example method signature
string ReplaceNametags(uriTemplate, params object[] args)
{
    /* insert magic here */
}

Reflection came to mind, maybe I could harvest the names of the inputs somehow, but I'm not that good with reflection, and all my attempts end up being wildly more complicated than it would be to give up on the idea altogether.

String.Format() came to mind, but ideally I wouldn't be constrained by the ordinal position of the provided arguments.

I've seen this behavior used all over the place (e.g. RestSharp, Swagger, ASP.NET Routing), but I'm not sure how to imitate it.

Thanks!


Solution

  • You could pass arguments as dynamic object, iterate through its keys and utilize Regex to perform replacement:

    private string ReplaceNameTags(string uri, dynamic arguments)
        {
            string result = uri;
            var properties = arguments.GetType().GetProperties();
            foreach (var prop in properties)
            {
                object propValue = prop.GetValue(arguments, null);
                //result = Regex.Replace(uri, $"{{{prop.Name}}}", propValue.ToString());
                  result = Regex.Replace(result, $"{{{prop.Name}}}", propValue.ToString());
            }
            return result;
        }
    

    Example use would be:

    ReplaceNameTags(uri, new { projectId, uploadId });