为什么字符串类型的默认值是null而不是空字符串?

243

在我可以安全地应用 ToUpper()StartWith() 等方法之前,测试所有字符串是否为 null 很烦人。

如果默认值的 string 是空字符串,则我不必进行测试,并且这会更加符合其他值类型(例如 intdouble)的一致性。此外,Nullable<String> 也是有意义的。

那么,为什么 C# 的设计者选择使用 null 作为字符串的默认值呢?

注意:这与这个问题相关,但更专注于为什么而不是该怎么做。


57
你认为这对于其他引用类型来说是一个问题吗? - Jon Skeet
20
不,只是因为我最初错误地认为字符串是值类型。 - Marcel
24
@Marcel:这是一个非常好的怀疑的理由。 - T.J. Crowder
7
@JonSkeet 是的,非常赞同。 (但你对于不可为空的引用类型讨论也并不陌生...) - Konrad Rudolph
8
@JohnCastle 我敢你去问那些理解三态值的数据库开发人员,看看他们是否愿意放弃 null 值。之所以 null 值不好是因为人们不会思考三态,人们只会想到左或右、上或下、是或否。关系代数需要一个三态值。 - jcolebrand
显示剩余3条评论
15个回答

2
一个字符串是一个不可变的对象,这意味着当给定一个值时,旧值并没有从内存中被清除,而是仍然存在于旧位置,新值被放置在新位置。因此,如果String a的默认值是String.Empty,那么当它被赋予第一个值时,它会浪费内存中的String.Empty块。
虽然这似乎微不足道,但当使用String.Empty作为默认值初始化大量字符串数组时,它可能会成为问题。当然,如果这将成为一个问题,您总是可以使用可变的StringBuilder类。

感谢您提到“第一次初始化”的事情。 - Marcel
3
初始化一个大数组会存在什么问题?因为如你所说,字符串是不可变的,数组中的所有元素只是指向相同的 String.Empty 的指针。我理解得对吗? - Dan Burton
2
任何类型的默认值都将所有位设置为零。 字符串 的默认值为空字符串的唯一方法是允许全零位作为空字符串的表示方式。有许多实现方式,但我认为没有一种方式涉及初始化对 String.Empty 的引用。 - supercat
其他答案也讨论了这一点。我认为人们已经得出结论,即将String类视为特殊情况并提供除所有位都为零以外的其他初始化方式是没有意义的,即使它是像String.Empty""这样的东西。 - djv
@DanV:更改string存储位置的初始化行为还需要更改所有具有string类型字段的结构体或类的初始化行为。这将代表.NET设计中相当大的变化,目前期望对任何类型进行零初始化,甚至不必考虑它是什么,只需保存其总大小即可。 - supercat

2

由于字符串是引用类型,引用类型的默认值为null。


1

既然您提到了 ToUpper(),而且正是通过这种用法我找到了这个线程,那么我会分享这个快捷方式 (string ?? "").ToUpper():

    private string _city;
    public string City
    {
        get
        {
            return (this._city ?? "").ToUpper();
        }
        set
        {
            this._city = value;
        }
    }

Seems better than:

        if(null != this._city)
        { this._city = this._city.ToUpper(); }

0
也许 string 这个关键字把你搞糊涂了,因为它看起来和其他 值类型 的声明一模一样,但实际上它只是 System.String 的别名,详细解释可以参考 this question
另外,在 Visual Studio 中的深蓝色和首字母小写可能会让人误以为它是一个 struct

3
object”关键字难道不也是如此吗?虽然必须承认,它比“string”用得少。 - user395760
2
由于intSystem.Int32的别名,你想说什么呢? :) - Thorarin
@Thorari @delnan:它们都是别名,但System.Int32是一个Struct,因此具有默认值,而System.String是一个Class,具有指针和默认值为null。它们在视觉上以相同的字体/颜色呈现。如果没有知识,人们可能会认为它们的作用方式相同(=具有默认值)。我的答案是基于认知心理学思想编写的 :-) - Alessandro Da Rugna
我相当确定是Anders Hejlsberg在Channel 9的一次采访中说过这句话。我知道堆和栈的区别,但C#的理念是普通程序员不需要知道。 - Thomas Koelle

0

可空类型直到2.0版本才出现。

如果在语言开始时就有可空类型,那么字符串将是不可空的,而string?将是可空的。但由于向后兼容性,他们无法这样做。

很多人谈论引用类型或非引用类型,但字符串是一个特殊的类,解决方案会被找到使其成为可能。


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