String、FormattableString和IFormattable的区别

58

FormattableString自C# 6.0版本开始引入。我们可以使用string对象来进行相同的字符串格式化,那么为什么还需要使用FormattableStringIFormattable呢?这三者有什么区别?

我的代码

        var name = "Pravin";
        var s = $"Hello, {name}";
        System.IFormattable s1 = $"Hello, {name}";
        System.FormattableString s2 = $"Hello, {name}";

首先,这会产生相同的结果,即'Hello Pravin'。

如果有人对此有更深入的了解,我可以得到更详细的答案吗?

2个回答

78

FormattableString是.NET 4.6中的新类型,只有在您尝试使用它时编译器才会使用它。换句话说,插入字符串文字的类型通常为string,使用string.Format构建,但如果您请求,则可以使用FormattableString(通过FormattableStringFactory)。

FormattableString由将传递给string.Format的格式字符串(例如"Hello, {0}")和按顺序传递以进行格式化的参数组成。关键是,在格式化之前捕获了此信息。

这使您可以适当地调整格式 - 最常见的是在不变的文化中执行格式,通常使用Invariant静态方法

当您将插入字符串文字分配给IFormattable变量时,也将使用FormattableString。在这种情况下,IFormattable.ToString(string, CultureInfo)实现忽略第一个参数,这可能是它使用显式接口实现的原因。

示例代码:

using System;
using System.Globalization;
using System.Threading;
using static System.FormattableString;

class Test
{
    static void Main()
    {
        var uk = CultureInfo.CreateSpecificCulture("en-GB");
        Thread.CurrentThread.CurrentCulture = uk;
        var germany = CultureInfo.CreateSpecificCulture("de-DE");
        string now = $"Default: it is now {DateTime.UtcNow}";
        Console.WriteLine(now); // UK format
        IFormattable x = $"Specific: It is now {DateTime.UtcNow}";
        Console.WriteLine(x.ToString("ignored", germany));
        FormattableString y = $"FormattableString: It is now {DateTime.UtcNow}";
        Console.WriteLine(FormattableString.Invariant(y));
        // Via using static
        Console.WriteLine(Invariant($"It is now {DateTime.UtcNow}")); 
    }
}

示例结果:

Default: it is now 16/02/2016 07:16:21
Specific: It is now 16.02.2016 07:16:21
FormattableString: It is now 02/16/2016 07:16:21
It is now 02/16/2016 07:16:21

5
由于string未实现IFormattable接口,因此当您将插值字符串转换为IFormattable时,使用FormattableString是唯一的选择。 - user4003407
@PetSerAI:你说得完全正确。不确定我当时在想什么。我会在到达办公室后进行编辑。 - Jon Skeet
@JonSkeet 我只是在查看 Microsoft Open XML SDK 代码的一行:RawOuterXml = Invariant($"");其中 RawOuterXml 和 xmlReader.Value 都是字符串。如果一个变量已经是字符串了,那么使用 Invariant 调用会有什么效果吗? - axeman
@axeman:我怀疑不是,但这可能是那种情况之一,使用"Invariant"进行多次调用比单独考虑每个调用更容易。 - Jon Skeet

7
作为旁注,https://www.meziantou.net/interpolated-strings-advanced-usages.htm涵盖了一些FormattableString允许您执行的示例(例如,自动参数化SQL语句)。
例如:
void ExecuteNonQuery(DbConnection connection, FormattableString formattableString)
{
    using (var command = connection.CreateCommand())
    {
        // Replace values by @p0, @p1, @p2, ....
        var args = Enumerable.Range(0, formattableString.ArgumentCount).Select(i => (object)("@p" + i)).ToArray();

        command.CommandType = System.Data.CommandType.Text;
        command.CommandText = string.Format(formattableString.Format, args);

        // Create parameters
        for (var i = 0; i < formattableString.ArgumentCount; i++)
        {
            var arg = formattableString.GetArgument(i);
            var p = command.CreateParameter();
            p.ParameterName = "@p" + i;
            p.Value = arg;
            command.Parameters.Add(p);
        }

        // Execute the command
        command.ExecuteNonQuery();
    }
}

using (var sqlConnection = new SqlConnection())
{
    sqlConnection.Open();
    ExecuteNonQuery(sqlConnection, $@"UPDATE Customers SET Name = {"Meziantou"} WHERE Id = {1}");
}


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