2

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!

4
  • You could try Replacing words in a string with values from Dictionary in c# Commented Jan 25, 2020 at 17:05
  • Thanks Anoop; interestingly, that's actually pretty close to what my first attempt looked like, and with a few oddball exceptions (like over/under-replacing tags in the string), it works pretty well. What I dislike though is I then wind up having to create a new Dictionary everywhere I want to perform a replacement, as well as re-inputing all the slugs to replace. It's effective, but not succinct, and curious if there is a more elegant solution. perhaps that approach, but wrapped in a more reusable way? Commented Jan 25, 2020 at 17:16
  • Maybe simply string uri = ReplaceNametags(uriTemplate, new object[] { projectId, uploadId}); and change the placeholders in "http://www.example.com/project/{param0}/data?uploadId={param1}";. Then in the method, loop args[] and string.Replace() $"{{param{i}}}", as in uriTemplate = uriTemplate.Replace($"{{param{i}}}", args[i].ToString()); Commented Jan 25, 2020 at 17:18
  • I would still go so far as to say string interpolation is your best bet in that case. Commented Jan 25, 2020 at 17:21

2 Answers 2

5

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 });
Sign up to request clarification or add additional context in comments.

1 Comment

I think this is pretty much exactly what I was looking for; thanks!
1

You can use positional placeholders instead of variable names, and document what variable goes to what position.

int projectId = 1; //documented as the first value (position 0)
int uploadId = 3; //documented as the second value (position 1)

//supplied by end users... say, loaded from config file
string uriTemplate = "http://www.example.com/project/{0}/data?uploadId={1}";

string uri = string.Format(uriTemplate, projectId, uploadId);

I've also seen this done with an empty string going in position 0, so it makes more sense for end users when the numbering starts at 1.

string uriTemplate = "http://www.example.com/project/{1}/data?uploadId={2}";
string uri = string.Format(uriTemplate, "", projectId, uploadId);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.