String.Format参数为空异常

61
下面的代码将抛出参数空异常。
var test = string.Format("{0}", null); 

然而,这将返回一个空字符串

string something  = null; 
var test = string.Format("{0}", something); 

只是好奇为什么第二段代码没有抛出异常。这是一个漏洞吗?


1
有趣的问题!请记得在以后使用代码块格式,这会使问题更易读。我已经为您修复了它。 - BradleyDotNET
谢谢您的编辑。当我准备编辑时,您已经完成了它 :) - Raj C
3个回答

77
区别在于第一个代码片段调用了string.Format(string, object[]),而第二个代码片段调用了string.Format(string, object)

null是第二个方法的有效参数(它只是第一个占位符的值),但不是第一个方法的有效参数(通常情况下,null将是占位符的数组)。特别是,请比较当抛出NullArgumentException时的文档:

string.Format(string, object)
formatnull

但是:

string.Format(string, object[])
formatargsnull

string.Format(string, object)视为实现某些内容的内容:

public static string Format(string format, Object arg0)
{
    return string.Format(format, new object[] { arg0 } );
}

所以经过一些替换,你的代码更接近于:

// Broken code
object[] args = null; // No array at all
var test = string.Format("{0}", args); 

// Working code
object[] args = new object[] { null }; // Array with 1 value
var test = string.Format("{0}", args); 

1
最后一个代码块终于让我恍然大悟! - Chris Cirefice
16
如果有人还不清楚在这种情况下编译器选择使用string.Format(string, params object[])而不是string.Format(string, object)的规则,可能需要阅读C#规范的"更好的函数成员"章节(在ECMA标准中是第14.4.2.2章,在当前的MS标准中是第7.5.3.2章)-- 这归结于null参数不需要展开params object[],而object[]是比object更具体的参数类型。 - user2819245
@supercat,你误解了一些东西——不需要进行任何转换。你可以直接将字面值 null 赋给对象数组,而无需进行任何转换(例如 object[] arr = null;),对此没有任何荒谬之处... - user2819245
@supercat,我明白你的意思了。你提到了MS规范中关于null字面量的隐式转换,这只在MS标准中写成这样,而不是在ECMA标准中——这是因为不同标准文档导致的典型误解...(叹气) - user2819245
1
@elgonzo:无论如何,我的观点是,虽然null字面量可以隐式转换为任何引用类型,但我不认为将其视为“更好”的匹配项适用于SiameseCat而不是Animal。在某些情况下,null字面量可能是一个重载的合法参数,但对于另一个重载则不是;让重载指示哪个应该是首选项似乎比让编译器选择那个最不可能准备接受它的选项更好。 - supercat
显示剩余6条评论

16
第二段代码片段调用以下重载:
Format(String, Object)

根据文档,这里的值可以为null。

第一个代码片段使用以下重载:

Format(String, Object[])  

根据文档,第二个值不能为Null


但是,在文档中也写着“由所有重载引发”。我有什么遗漏吗? - Amit Joki
2
@AmitJoki,文档中你错过了一部分:“条件:format为空。” - user2819245
@AmitJoki 它说明了哪些参数为空会导致它被抛出。 - Servy
@elgonzo 是的!明白了。 - Amit Joki

0

现有答案中没有提到的一个小点,几乎使问题无意义:

ArgumentNullException 的完整消息为:

值不能为 null。
参数名: args

这里的问题的一部分是 null 可以是任何类型。显式地将其转换为 stringobject(或使用 C# 中的 default() 功能)可以避免出现问题。


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