String.Format有bug吗?

时间:2015-02-06 17:55:56

标签: c# string-formatting

当我使用自定义格式化程序并将{{{0:,;'{{0}}'}}}传递给String.Format时,它会通过格式化程序,;'{{0}}'}

为什么会有一个尾随支架?这是我的问题还是String.Format


我写了一个加入IEnumerables的IFormatProvider / ICustomFormatter。它将传递的格式字符串(一次)拆分为';'并使用第一部分作为连接字符串,第二部分作为元素的格式字符串。例如,

{0:,;'{{0}}'}

会导致格式化程序被传递,;'{0}',它将分别作为连接和元素格式字符串分为,'{0}'。然后它会返回

String.Join(",", arr.Select((elem, index) => String.Format("'{0}'", elem, index))

当我使用

({0:,;'{{0}}'})

作为我的格式字符串,我得到了

('elem0','elem1', ... )
正如我所料,

仅当我尝试使用大括号而不是括号时才会出现此错误。


适用于LINQPad的代码:

void Main()
{
    // works
    String.Format(new JoinFormatter(), "({0:, ;'{{0}}'})", (object)new[] { "a", "b", "c" }).Dump();

    // doesn't work
    String.Format(new JoinFormatter(), "{{{0:, ;'{{0}}'}}})", (object)new[] { "a", "b", "c" }).Dump();
}

public class JoinFormatter : IFormatProvider, ICustomFormatter
{
    public ICustomFormatter Other;

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

    public string Format(string format, object arg, IFormatProvider provider)
    {
        if (arg == null || format == null)
            if (Other == null)
                return String.Format("{0}", arg);
            else
                return Other.Format(format, arg, provider);

        if (arg is string || !(arg is IEnumerable))
            if (Other != null)
                return Other.Format(format, arg, provider);
            else if (arg is IFormattable)
                return ((IFormattable)arg).ToString(format, provider);
            else
                return arg.ToString();

        string join, elemf;
        var index = 0;
        while (true)
        {
            index = format.IndexOf(';', index);
            if (index < 0)
            {
                join = format;
                elemf = null;
                break;
            }

            if (index == 0)
            {
                join = "";
                elemf = format.Substring(1);
                break;
            }

            if (index == format.Length - 1)
            {
                join = format.Substring(0, format.Length - 1);
                elemf = null;
                break;
            }

            if (index > 0 && format[index - 1] == '!')
                if (index > 1 && format[index - 2] == '!')
                {
                    join = format.Substring(0, index - 1);
                    elemf = format.Substring(index + 1);
                }
                else
                    continue;

            join = format.Substring(0, index);
            elemf = format.Substring(index + 1);
            break;
        }


        return String.Join(join, ((IEnumerable)arg).Cast<object>().Select((o, i) => elemf == null ? o.ToString() : String.Format(provider, elemf, o, i)));
    }
}

1 个答案:

答案 0 :(得分:0)

为了实现我的预期结果,我改为使用{{ {0:,;'{{0}}'} }}。添加空格得到String.Format以按照我想要的方式解释字符串。使用{{{<ArgNum>:<FormatStr>}}},它将前两个右括号解释为FormatStr的一部分,将最后一个右括号解释为终止参数格式说明符。虽然我希望第一个右大括号终止参数格式说明符,但我希望最后两个右大括号将右大括号附加到输出。