C# 中的动态字符串模板
Dynamic String Templating in C#
我正在寻找一种执行字符串插值的方法,但是模板字符串提前在变量中,而不是使用 true 字符串解释,其中 $" {a}{b}" 立即参数化并返回。
这在很多地方都会有用,但最明显的例子是,我正在编写一个 ETL(提取转换加载)管道,其中有许多我需要访问的不同 REST API。相同的两个参数重复出现在不同的 URI 中,我想用用户提供的值动态替换它们。下面列出了两个这样的例子。
http://www.example.com/projects/{projectId}/data
- 例如,给定
1
的 projectId
,我希望 http://www.example.com/projects/1/data
http://www.example.com/project/{projectId}/data?uploadId={uploadId}
如果我在 运行 时有可用的值,例如
,这可以使用字符串插值轻松完成
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" */
但是我想提前构建这些参数化字符串,并能够用我在该上下文中可用的任何变量替换它们。换句话说,在伪代码中:
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 */
}
我想到了反思,也许我可以以某种方式收获输入的名称,但我对反思并不擅长,我所有的尝试最终都比放弃更复杂完全是个主意。
我想到了 String.Format()
,但理想情况下我不会受到所提供参数的顺序位置的限制。
我看到到处都在使用这种行为(例如 RestSharp、Swagger、ASP.NET 路由),但我不确定如何模仿它。
谢谢!
您可以将参数作为动态对象传递,遍历其键并利用 Regex 执行替换:
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;
}
示例用法为:
ReplaceNameTags(uri, new { projectId, uploadId });
您可以使用位置占位符代替变量名,并记录哪个变量位于哪个位置。
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);
我还看到这是在位置 0 处使用空字符串完成的,因此当编号从 1
开始时,对最终用户来说更有意义。
string uriTemplate = "http://www.example.com/project/{1}/data?uploadId={2}";
string uri = string.Format(uriTemplate, "", projectId, uploadId);
我正在寻找一种执行字符串插值的方法,但是模板字符串提前在变量中,而不是使用 true 字符串解释,其中 $" {a}{b}" 立即参数化并返回。
这在很多地方都会有用,但最明显的例子是,我正在编写一个 ETL(提取转换加载)管道,其中有许多我需要访问的不同 REST API。相同的两个参数重复出现在不同的 URI 中,我想用用户提供的值动态替换它们。下面列出了两个这样的例子。
http://www.example.com/projects/{projectId}/data
- 例如,给定
1
的projectId
,我希望http://www.example.com/projects/1/data
- 例如,给定
http://www.example.com/project/{projectId}/data?uploadId={uploadId}
如果我在 运行 时有可用的值,例如
,这可以使用字符串插值轻松完成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" */
但是我想提前构建这些参数化字符串,并能够用我在该上下文中可用的任何变量替换它们。换句话说,在伪代码中:
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 */
}
我想到了反思,也许我可以以某种方式收获输入的名称,但我对反思并不擅长,我所有的尝试最终都比放弃更复杂完全是个主意。
我想到了String.Format()
,但理想情况下我不会受到所提供参数的顺序位置的限制。
我看到到处都在使用这种行为(例如 RestSharp、Swagger、ASP.NET 路由),但我不确定如何模仿它。
谢谢!
您可以将参数作为动态对象传递,遍历其键并利用 Regex 执行替换:
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;
}
示例用法为:
ReplaceNameTags(uri, new { projectId, uploadId });
您可以使用位置占位符代替变量名,并记录哪个变量位于哪个位置。
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);
我还看到这是在位置 0 处使用空字符串完成的,因此当编号从 1
开始时,对最终用户来说更有意义。
string uriTemplate = "http://www.example.com/project/{1}/data?uploadId={2}";
string uri = string.Format(uriTemplate, "", projectId, uploadId);