如何使用字典使字符串插值生效

3

我有一个带有“键值对”的字典,需要使用字符串插值,然后根据命名参数映射字符串。请帮忙。

// code removed for brevity
var rawmessage = "Hello my name is {Name}"; // raw message
var dict= new Dictionary<string, object>();
dict.Add("{Name}", response.Name);

我希望能够做到以下操作:

我想要实现类似以下的功能:

// Pseudo code
$"Hello my name is {Key}", dict;

我目前找到的解决方案:

     var message = parameters.Aggregate(message, 
(current, parameter) => current.Replace(parameter.Key, parameter.Value.ToString()));

这段代码是没有问题的,但我的经理希望我使用字典的字符串插值。我不确定如何实现,请指导我。


字符串插值只是围绕着 string.Format 的语法糖,你不能像这样使用预设的字符串。 - DavidG
现在,为什么要负评!说真的! - Unbreakable
不是我的问题,这是一个有效的问题,只是无法实现。 - DavidG
你能解释一下使用字符串插值的意思吗?我想看一个更好的例子。 - sTrenat
@sTrenat:我有一个字典,里面有5个名称值对,我想使用字符串内插法将命名参数(作为键存在于字典中)映射到它们各自的值。但是我不想使用String.Replace。有没有其他方法? - Unbreakable
显示剩余3条评论
3个回答

10
问题在于,C#中的string interpolation只是对string.Format的语法糖包装。这些字符串会被编译成相同的代码。以这段代码为例:
public string GetGreeting1(string name)
{
    return string.Format("Hello {0}!", name);
}

public string GetGreeting2(string name)
{
    return $"Hello {name}!";
}

两种方法的IL输出相同:

GetGreeting1:
IL_0000:  ldstr       "Hello {0}!"
IL_0005:  ldarg.1     
IL_0006:  call        System.String.Format
IL_000B:  ret         

GetGreeting2:
IL_0000:  ldstr       "Hello {0}!"
IL_0005:  ldarg.1     
IL_0006:  call        System.String.Format
IL_000B:  ret  

所以,您提供的解决方案是完全有效的,我之前也使用过。唯一可能的改进是,如果您打算进行大量替换,那么如果切换到使用 StringBuilder,您可能会发现性能有所提升。您可能可以在 Nuget 上找到一个库来为您完成这个操作,但这可能只是为了您的目的而过度了。

作为额外的内容,我创建了一个扩展类。额外的奖励是,我还添加了一个使用反射来进行替换的具有任意数量参数的对象方法:

public static class StringReplacementExtensions
{
    public static string Replace(this string source, Dictionary<string, string> values)
    {
        return values.Aggregate(
            source,
            (current, parameter) => current
                .Replace($"{{{parameter.Key}}}", parameter.Value));
    }

    public static string Replace(this string source, object values)
    {
        var properties = values.GetType().GetProperties();

        foreach (var property in properties)
        {
            source = source.Replace(
                $"{{{property.Name}}}", 
                property.GetValue(values).ToString());
        }

        return source;
    }
}

并且使用方法如下:

var source = "Hello {name}!";

//Using Dictionary:
var dict = new Dictionary<string, string> { { "name", "David" } };
var greeting1 = source.Replace(dict);
Console.WriteLine(greeting1);

//Using an anonymous object:
var greeting2 = source.Replace(new { name = "David" });
Console.WriteLine(greeting2);

7
这段代码可以正常工作,但我的经理非常希望我使用带字典的字符串插值。我不确定如何实现。
你不能这样做。C#字符串插值不是模板引擎,而是编译时特性,它会转换为String.Format调用。这就是为什么你也不能在常量表达式中使用字符串插值。
我想使用字符串插值将命名参数(字典中的键)映射到它们各自的值。但我不想使用String.Replace。有没有其他方法?
实际上,有几个你可以使用的模板引擎(主要用于日志记录),因此你不需要重新发明轮子。例如,你可能会发现Serilog很有趣。
另请参阅此线程:.NET中进行字符串模板化的好方法是什么?

1
以上答案并不完全正确,它们声称插值字符串只是对 string.Format() 的语法糖,但实际上插值字符串还能做更多的事情。这使得使用 FormattableString 和自定义的 IFormatProvider/ICustomFormatter 可以实现您所需的功能,具体操作如下:
public class DictionaryFormatter : IFormatProvider, ICustomFormatter
{
    private Dictionary<string, string> _dict;
    public DictionaryFormatter(Dictionary<string, string> dict)
    {
        _dict = dict;
    }
    public string Format(string? format, object? arg, IFormatProvider? formatProvider)
    {
        var key = arg?.ToString() ?? String.Empty;
        return _dict[key];
    }

    public object? GetFormat(Type? formatType)
    {
        if (formatType == typeof(ICustomFormatter))
            return this;
        else
            return null;
    }
}

使用方法:

FormattableString x = $"This is an interpolated string with the first argument being: {"One"} and the second being {"Two"}";
var dict = new Dictionary<string, string>() {{"One", "First Value"}, {"Two", "Second Value"}};
var result = x.ToString(new DictionaryFormatter(dict));
Console.WriteLine(x.Format);
Console.WriteLine(string.Join(',', x.GetArguments()));
Console.WriteLine(result);

输出:

"This is an interpolated string with the first argument being {0} and the second being {1}"
"One,Two"
"This is an interpolated string with the first argument being First Value and the second being Second Value"

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