6

在格式字符串的全文是静态的并且在编译时已知的情况下,丢失的格式字符串参数不应该是编译时错误,或者至少是警告吗?

ReSharper 捕捉到了这一点,但它只是一个带下划线的曲线。我的印象是这会触发一般的编译时错误:

string x = string.Format("soeuotnh {0}");

有什么方法可以触发此类错误的警告,而无需通过 FxCop 或其他方式运行我的代码?即使是 C/C++ 编译器也会针对如此明显的错误触发警告/错误(尽管它们通常不会检查类型安全)。

4

7 回答 7

2

可能是一个警告,但它应该是吗?好吧,我想这取决于编译器团队,它不像String.Format是 C#语言的一部分。

这不是 C;你没有调用未定义的行为或任何东西,该方法可以简单地处理丢失的参数,并且假设(我假设......)当它抛出异常时你会很快捕获它。没有什么“危险”的,这只是一个逻辑错误。

于 2012-04-17T16:36:47.843 回答
2

除了您提到的自动检测这种情况之外,我认为没有其他方法。至于为什么会发生这种情况,Format 方法与重载相匹配(String, params Object[]),其参数在文档中定义如下:

public static string Format(
    string format,
    params Object[] args
)

format 类型:System.String
复合格式字符串(请参阅备注)。

args 类型:System.Object[] 包含个或多个要格式化的对象的对象数组。

由于params定义了可变数量的参数(包括零个参数),这就是为什么没有抛出编译时异常的原因。

编辑:

由于编译器可以选择有效的重载,因此您不会收到编译时错误。所以这不再是编译器问题,最好的办法是使用代码质量工具 Resharper 来检测这种情况。

于 2012-04-17T16:37:13.513 回答
0

一些 C 编译器会解析格式字符串,因为格式字符串与参数不匹配会导致严重的崩溃错误——甚至更糟糕的是,安全错误。但是,在 C# 中,您只会在调用站点遇到异常,因此这并不重要。

编译器可以做到这一点,但这需要将代码识别string.Format为特殊情况,并且(更糟糕的是)需要有人在 C# 编译器中编写格式字符串解析器。所有这些都是为了警告您每次执行时都会崩溃的代码。

这样做的一个大问题是,许多人在编译时将所有警告都打开并将警告作为错误,这意味着添加此警告将破坏他们的构建。任何人在其代码的黑暗角落中的一些错误格式字符串从未执行过,将突然无法构建他们的产品。这些人会抱怨。

于 2012-04-17T16:48:55.823 回答
0

正如已经说过的,这不是编译器要做或应该担心的事情。

在执行以下操作时,您希望编译器如何表现:

string format = "{0}";
List<string> parms = new List<string> { "Hello" };

if (DateTime.Now.Second % 2 == 0)
{
    format += " {1}";
    parms.Add("World");
}

Console.WriteLine(format, parms.ToArray());
于 2012-04-17T16:50:43.357 回答
0

Resharper针对这种情况显示警告:“格式化字符串中不存在参数”。

于 2012-04-17T16:55:47.733 回答
-1

该方法的“格式”参数不是常数。所有不是常量的东西都不能在编译时检查。

它可以通过各种方法在运行时组合,甚至可以是用户输入...(恐怖!)

这就是为什么它不是编译时错误。

编辑:好的,如果它是一个常量表达式,可以对其进行分析并生成警告。但这里是Eric Lipert 对另一个有点适用的问题的回答:收益高于成本。

这是否是值得为 String.Format (可能还有其他字符串格式函数)花费特殊情况场景的真正好处……这是一个艰难的决定。

于 2012-04-17T16:45:13.953 回答
-1

我已在 Microsoft Connect 上提交了考虑此功能的请求,因为我认为

  • 回答说“如果代码路径不是很热,人们宁愿他们的代码在运行时编译并失败”只是荒谬的,并且在非解释语言中没有位置,尤其是在没有明确定义的强类型语言中放置这样一个与 C# 一样,类型安全的重要性。
  • 说编译器在编译时实际上无法(永远)推导出格式字符串和参数数组的答案也是不正确的。是的,有时编译器无法在编译时推断出一个或另一个(或两者),并且对此无能为力,但在许多其他时候,它拥有完整的信息可供使用。
  • 说这完全不是编译器的工作只是因为规范没有提到对这种行为发出警告的答案错过了这样一个事实,即规范是编译器应该实现的最低要求,并且编译器是免费的(并且确实确实在很大程度上)超越和超越,只要它不与规范冲突。
  • 说 C 编译器也不这样做的答案是完全错误的 - 我已经发布了其他示例
  • 说我发布的代码示例在运行时不会引发异常的答案是公然错误的(尽管从那时起大多数都已被编辑)。

归根结底,这是一种“可以,不可以,也许应该”的情况。我试图确保我无法在编译器(不是第三方软件)中设置任何东西以使其警告更具侵略性,或者如果有某种方式我可以更改我的代码以使其抛出异常(例如,将所有内容声明为 const),但事实证明(到目前为止)这是不可能的。无论 Visual Studio 团队对我在 MS Connect 上打开的问题的反应如何,事实仍然是编译器肯定可以在编译时捕获大量字符串格式异常,这是一个好处......但它仍然存在VS 团队来确定它是否值得实施。

于 2012-04-18T18:16:46.760 回答