【问题标题】:Why cannot I use String.Contains() if default string is null?如果默认字符串为空,为什么我不能使用 String.Contains()?
【发布时间】:2016-03-01 11:59:37
【问题描述】:

来自MSDN doc

public bool Contains(
    string value
)

返回值:true 如果 value 参数出现在这个字符串中,或​​者如果 value 是空字符串 ("");否则,false

例外:ArgumentNullExceptionvaluenull

例子:

string s = string.Empty; //or string s = "";
Console.WriteLine(s.Contains("Hello World!")); //output: False

如果我将其更改为:

try
{
   string s = null; //or string s;
   Console.WriteLine(s.Contains("Hello World!"));
}
catch (Exception e)
{
   Console.WriteLine(e.Message);
}

它会抛出一个错误消息:Object reference not set to an instance of an object 因为string 没有来自Default Values Table (C# Reference) 的默认值(如""),

请回到示例,如果我声明s,代码将起作用:

string s = "";

现在,Object s 被设置为一个对象的实例

所以,我的问题是:MSDN 是否忘记了类似:s 不能为 null

为了检查,我试过了:

string s = null;
Console.WriteLine(!string.IsNullOrEmpty(s) ? s.Contains("Hello World!") : false);

它应该可以工作。

【问题讨论】:

标签: c# .net string


【解决方案1】:

您使用实例更改了

myString.Contains(anotherString)

这里myString 是您调用Contains 方法的实例,而anotherString 是传递给该方法的。如果此值为null,该方法将抛出ArgumentNullException

另一方面,当将 instance 更改为 null 时,它肯定会导致 NRE,因为您不能在空引用上调用任何成员。但是,如果将其设置为 string.empty Contains 将返回 false,因为空字符串不包含 anything(特别是 string.empty 不包含 "Hello World",但是 "Hello world" 包含空字符串)。

所以下面返回false

Console.WriteLine(string.Empty.Contains("Hello World"));

虽然这会返回 true:

Console.WriteLine("Hello World".Contains(string.Empty));

无论如何,您要检查的是空字符串是否包含在任何其他字符串中:

var retVal = myString.Contains(string.empty);

应该返回true

此外myString.Contains(null) 导致ArgumentNullException

在另一边null.Contains(aString) 通往 NRE。

【讨论】:

  • 很好的解释。 +1
【解决方案2】:

新的编译器允许您通过简化的条件检查来做到这一点。

string s = null;
Console.WriteLine(s?.Contains("Hello World!"));

【讨论】:

    【解决方案3】:

    听起来这个问题更多的是关于 value 类型(不能为 null)和 reference 类型(可以是)之间的区别。在 C# 和其他 OO 语言中,它与内存处理有关。

    您的 MSDN 文章中列出的值类型都是已知大小 - 例如int始终为 32 位大小等。在引擎盖下,这些都是 structs。由于无论值如何,它们的大小都是固定的,因此 C# 将它们存储在 call stack 上。由于null 的定义不涉及任何内容,因此它没有大小。以固定大小存在的东西也没有大小存在是没有意义的。

    如果您仔细阅读 MSDN 上的 string 文档,您会发现 string 是一个 而不是结构。这是因为字符串可以是您喜欢的任何长度,因此必须将其存储为指向heap 上某些数据的指针。当您声明一个引用类型变量时,它会在堆栈上创建一个指向堆上某个位置的指针,但是在您给该变量一个值之前,该地址不会有任何东西。 在此之前,该变量的指针一直在指向并且内存实际上什么都不包含 - 即null,尝试查找“Hello World!”是没有意义的。什么都没有。一个空字符串仍然是一个字符串,但 null 实际上什么都不是。

    这可能比您预期的更详细,但是了解一种语言的基本原则是一件好事,即使您每天都不需要它们。 This article 非常值得一读,如果你想更深入一点。 null 的想法可能是一个奇怪的概念,但一旦你掌握了它,这一切都是有道理的,诚实的!

    【讨论】:

    • 哦。对不起。但是我还没有阅读任何文档说string 是一个类而不是一个结构。我同意你的观点,string 是一种存储在堆中的引用类型。但是如果stringclass,我可以为string 声明属性,不是吗?也许我不明白你的意思。
    • 它没有明确说明,但如果你查看stringint 的语法,一个是class,一个是struct。至于属性,string 类有两个属性,LengthChars,但是它们被定义为只能获取它们的值,不能设置它们——这没有意义!
    • stringclass 是 2 个对象。它不适用于structintstructint 是值类型,而不是引用类型。你无法比较它们。
    猜你喜欢
    • 1970-01-01
    • 2015-06-03
    • 2012-12-29
    • 1970-01-01
    • 2016-12-30
    • 1970-01-01
    • 2019-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多