C# - 动态字符串插值

5
我正在尝试在特定的上下文/范围内使用可用变量动态格式化一些字符串。
这些字符串将包含像{{parameter1}}{{parameter2}}之类的部分,而这些变量将存在于我将尝试重新格式化字符串的作用域中。变量名应匹配。
我寻找类似于动态字符串插值方法或如何使用FormattableStringFactory的东西,但是我没有找到真正满足我的需求的内容。
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 });

是否有现成的解决方案,还是我应该在MagicMethod中使用反射(或类似方式)将retrievedString中的这些部分替换为作为参数给出的匿名对象的匹配成员?

编辑:

最终,我创建了一个扩展方法来处理此问题:

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();
}

我会这样称呼它:

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

现在,我不再使用双括号。

在C#中没有任何东西可以做到这一点,你需要一个神奇的方法。 - DavidG
3个回答

8
你可以使用反射结合匿名类型来实现这一点:
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;
}

然后像这样调用它:

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

嗨,DavidG,谢谢你提供这个方法。如果我找不到更“本地”的.NET解决方案,这正是我想要做的。我将使用它与StringBuilder,谢谢! - Jin-K

3

我猜您遇到的困难是替换字符串中的某些内容,您可以使用 Replace( string oldValue, string newValue ) 方法将其替换为想要的数据。

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);

编辑

作者提到他正在寻找一个可以接受参数并迭代列表的东西。这可以通过以下方式实现:

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;
    }

函数changeTagWithText将返回:

"今天我们是Bar Foo"

使用此方法,您可以将所有标签添加到字典中,并自动替换所有标签。

我假设参数和输入字符串是动态的,但这可能会完成工作。 - DavidG
你好,感谢您的回复。问题在于参数列表将是可变的,因此我更喜欢使用将其作为参数并迭代列表的方法。 另一个问题是,我希望以高效的方式完成它,“string.Replace”:它不是每次都会创建一个新字符串吗? - Jin-K

1
如果您知道参数的顺序,可以使用string.Format()方法(msdn)进行编程。那么您的代码将如下所示:
var parameter1 = DateTime.Now.ToString();
var parameter2 = "Hello world!";
var retrievedString = "{{0}} Today we're {{1}}";
var result = string.Format(retrievedString, parameter2, parameter1);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接