String.Format() - 重新传递参数但添加更多参数

6
我希望能够做类似这样的事情:
public string GetMessage(params object otherValues[]) {
    return String.Format(this.Message, this.FirstValue, otherValues);
}

所以,我想将一组参数重新传递给 String.Format() 但又要添加新的参数。

知道我们可以“重建”一个新的对象数组,但这似乎不是最好的方法,你认为应该采用什么方式呢?

6个回答

17
public string GetMessage(params object[] otherValues)
{
    return String.Format(this.Message, new[] { this.FirstValue }.Concat(otherValues).ToArray<object>());
}

不幸的是,ToArray() 会建立一个新的结构。 - Luciano

3
您可以使用ConcatToArray扩展方法:
public string GetMessage(params object[] otherValues) 
{
    var values = new[] { this.FirstName }.Concat(otherValues).ToArray();
    return String.Format(this.Message, values);
}

这正是我正在寻找的 :-) 它不会有问题。我会添加它。谢谢。 - Darin Dimitrov
2
这会将 this.FirstName 放在 otherValues 的第一个元素之前,就像 OP 在他们的问题中所描述的那样吗? - Katie Kilian

1

如果通常只有很少的其他参数,我会使用现有的重载:

public string GetMessage(params object[] otherValues) {
    if (otherValues == null) return string.Format(this.Message, this.FirstValue);

    switch (otherValues.Length)
    {
        case 0:
            return string.Format(this.Message, this.FirstValue);
        case 1:
            return string.Format(this.Message, this.FirstValue, otherValues[0]);
        case 2:
            return string.Format(this.Message, this.FirstValue, otherValues[0], otherValues[1]);
        default:
            return string.Format(this.Message, new[] { this.FirstValue }.Concat(otherValues).ToArray()); 
    }
}

1

预处理消息

如果您不想在每个 GetMessage(...) 调用中创建一个新数组,您可以仅在开始时插入FirstValueMessage一次即可。然后,GetMessage(...) 就只使用 otherValues 参数来执行 string.Format(...)

Message 属性在设置了 FirstValue 后仅初始化一次,例如在构造函数或类似以下方式的 init 方法中:

void InitMessage()
{
    Message = String.Format(Message, FirstValue, "{0}", "{1}", "{2}", "{3}", "{4}");
}

InitMessage 方法将 Message 中的第一个索引初始化为 FirstValue,其余索引为 "{index}",即 "{0}", "{1}", "{2}" 等(允许有比消息索引更多的 params 元素)。

现在,GetMessage 可以直接调用 String.Format,无需进行任何数组操作,如下所示:

public string GetMessage(params object[] otherValues)
{
  return String.Format(Message, otherValues);
}

示例:

假设以下属性值:
this.Message = "第一个值是 '{0}'。其他值为 '{1}' 和 '{2}'。"this.FirstValue = "蓝色"

InitMessageMessage 更改为:
"第一个值是 '蓝色'。其他值为 '{0}' 和 '{1}'。"

GetMessage 调用
GetMessage("绿色", "红色")

结果为
"第一个值是 '蓝色'。其他值为 '绿色' 和 '红色'。"


@brernder:有趣的方法。在其他问题中可能会有用。但是由于您正在使用Concat(),因此似乎需要更多的工作,因为在格式中直接使用Concat()也可以解决它。 - Luciano
你是对的。我已经通过在InitMessage方法中的String.Format调用中添加"{...}"参数来更新答案。 - brgerner

0

如果你真的无法为数组创建另一种结构,那么另一种混乱的方法是使用正则表达式绕过格式。

private string FormatEval(Match m)
{
    int val = -1;
    string formatted = m.Value;
    if (int.TryParse(m.Groups["index"].Value, out val))
        formatted = val == 0 ? this.FirstValue : "{" + (val - 1).ToString() + "}";
    return formatted;
}

public string GetMessage(params object[] otherValues)
{
    string format = Regex.Replace(this.Message, @"\{(?<index>\d+)\}", FormatEval);
    return string.Format(format, otherValues);
}

基本上只需解析格式字符串以获取格式化标记({0},{1})等,并递减它们的索引。如果标记最初是 {0},则将其替换为 this.FirstName 字符串。

本质上,这样做的目的是手动执行 String.Format 的第一步,然后将生成的字符串传递给真正的 String.Format 方法来完成剩余部分。


0

传递离散元素

为避免在每个GetMessage调用中创建数组,您可以通过其离散元素传递otherValues

public string GetMessage(params object[] otherValues)
{
  return String.Format(Message,
                       FirstValue,
                       GetOrDefault(otherValues, 0),
                       GetOrDefault(otherValues, 1),
                       GetOrDefault(otherValues, 2),
                       GetOrDefault(otherValues, 3),
                       GetOrDefault(otherValues, 4));
}

private object GetOrDefault(object[] otherValues, int index)
{
  if (otherValues == null)
    return null;

  if (index < otherValues.Length)
    return otherValues[index];

  return null;
}

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