C# String.Format 可选参数

5
我想使用 string.Format可选参数
public static void Main(string[] args)
{
    // Your code goes here
    // Console.WriteLine(string.Format("{0} {1}", "a", "b"));
    Console.WriteLine(string.Format("{0} {1}", "a"));
}

例如,参数{1}可以是可选的,并且具有默认值。

你能帮我做到这一点吗?


3
我认为你不能用 String.Format 来实现这个,你想要达成什么目的?也许你可以使用 String.Join 来连接不确定数量的字符串元素。 - Habib
4个回答

9

这取决于你所说的“可选参数”的含义。

如果你想自动将null替换为默认值,最简单的方法是在参数中使用null合并运算符:

String.Format("{0} {1}", 
              "a",
              someNullableVariableContainingB ?? "default value");

如果您想要为多个String.Format调用重复使用相同的格式化字符串,例如:
var myFormatString = "{0} {1}";
var string1 = String.Format(myFormatString, "a", "b");
var string2 = String.Format(myFormatString, "a");

如果你提供的参数不足,那么你就没办法了:String.Format会抛出一个异常,并且没有办法在格式字符串中指定“可选参数”。你需要使用其他方法来代替String.Format,例如自定义方法,用于将缺失的参数替换为其预期的默认值。


这不是可选参数。您至少为占位符“{1}”传递了某些值。 - CriketerOnSO
@CriketerOnSO:这取决于OP想要做什么。我会详细解释我的答案。 - Heinzi
@CriketerOnSO 没有传递值的情况下,使用 String.Format 是无法实现这一点的。 - D Stanley
1
谢谢Heinzi的建议,但我有一个问题。我在资源文件中定义了“{0} {1}”,我不知道最终用户是否会提供所有参数,如果最终用户没有提供所有参数,我将会遇到异常。因此,我想使用{1}作为可选参数。 - Kernel Med
@KernelMed 你不能这样做 - 你必须至少有和格式中索引值一样多的参数。 - D Stanley

3
  private static Regex curlyBracketRegex = new Regex("\\{(.+?)\\}");

  private static string OptionalFormat(string formatString, params object[] args)
  {
        var numberOfArguments = curlyBracketRegex.Matches(formatString).Count;

        var missingArgumentCount = numberOfArguments - args.Length;
        if (missingArgumentCount <= 0) //more argument or just enough
            return string.Format(formatString, args);

        args = args.Concat(Enumerable.Range(0, missingArgumentCount).Select(_ => string.Empty)).ToArray();
        return string.Format(formatString, args);
  }

上述方法适用于简单格式字符串。正则表达式检测花括号。如果匹配数量高于传递的参数数目,则会创建一个新数组,将原始数组与空字符串组合在一起。

示例:OptionalFormat("{0}#{1}", "apple") //apple#


1
您可以创建一个扩展方法:

public static string MyFormat(this string s, int i, params string[] args){
    var t = new List<string>(args);
    for(var c = t.Count; c < i; ++c)
        t.Add(String.Empty); // or other default

    return String.Format(s, t.ToArray());
}

并调用:

"{0}:{1} - {2},{3},{4}".MyFormat(5, "ping", "fnord");

然而,它强制你按顺序指定参数,所以如果你想设置{4},就不能跳过{3}。但是你可以添加:

for(var x = 0; x < args.Count; ++x){
    if(args[x] == null) args[x] = String.Empty;

并调用:

"{0}:{1} - {2},{3},{4}".MyFormat(5, "ping", null, "pong");

将 {0} 和 {2} 设置为默认值 String.Empty,但保留 {1}、{3} 和 {4}。

你可以自动确定 i 的值,但这种方式更加简单易懂。


1
这个扩展方法不限制参数数量。它可以处理像"{0}""{0} {1}""{0} {1} {2}"等字符串。 小缺点是你需要先提供可选参数,然后是非可选参数。应该反过来,但不幸的是params关键字的本质禁止了这样做。 主要缺点是它忽略了花括号中的数字(尽管解决方案也可以重新设计以包括这一点)。
    public static string FormatOpt(this string s, string optional, params string[] param)
    {
        StringBuilder result = new StringBuilder();
        int index = 0;
        bool opened = false;
        Stack<string> stack = new Stack<string>(param.Reverse());

        foreach(var c in s)
        {
            if (c == '{')
            {
                opened = true;
                index = result.Length;
            }
            else if (opened && c == '}')
            {
                opened = false;
                var p = stack.Count > 0 ? stack.Pop() : optional;
                var lenToRem = result.Length - index;
                result.Remove(index, lenToRem);
                result.Append(p);
                continue;
            }
            else if (opened && !Char.IsDigit(c))
            {
                opened = false;
            }

            result.Append(c);
        }

        return result.ToString();
    }

并且预期有以下结果:

string res1 = "result: {0}, {1}, {2}, {3}".FormatOpt("optional", "first param", "second param");
// result: first param, second param, optional, optional

string res2 = "result: {0}, {1}, {2}, {3}".FormatOpt("optional", "first param");                 
// result: first param, optional, optional, optional

string res3 = "result: {0}, {1}, {2}, {3}".FormatOpt("optional");                                
// result: optional, optional, optional, optional

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