C# 为什么字符串类型的默认值是 null 而不是空字符串?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14337551/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is the default value of the string type null instead of an empty string?
提问by Marcel
It's quite annoying to test all my strings for null
before I can safely apply methods like ToUpper()
, StartWith()
etc...
这是很烦人的测试我所有的字符串null
之前,我可以放心地运用类似的方法ToUpper()
,StartWith()
等...
If the default value of string
were the empty string, I would not have to test, and I would feel it to be more consistent with the other value types like int
or double
for example.
Additionally Nullable<String>
would make sense.
如果的默认值string
是空字符串,我就不必测试,我会觉得它与其他值类型更一致,例如int
或double
。另外Nullable<String>
会有意义。
So why did the designers of C# choose to use null
as the default value of strings?
那么为什么 C# 的设计者选择使用null
作为字符串的默认值呢?
Note: This relates to this question, but is more focused on the why instead of what to do with it.
注意:这与这个问题有关,但更侧重于为什么而不是如何处理它。
采纳答案by Habib
Why is the default value of the string type null instead of an empty string?
为什么字符串类型的默认值是 null 而不是空字符串?
Because string
is a reference typeand the default value for all reference types is null
.
因为string
是一个引用类型,所有引用类型的默认值都是null
.
It's quite annoying to test all my strings for null before I can safely apply methods like ToUpper(), StartWith() etc...
在我可以安全地应用 ToUpper()、StartWith() 等方法之前,测试我所有的字符串是否为空是很烦人的......
That is consistent with the behaviour of reference types. Before invoking their instance members, one should put a check in place for a null reference.
这与引用类型的行为一致。在调用它们的实例成员之前,应该检查空引用。
If the default value of string were the empty string, I would not have to test, and I would feel it to be more consistent with the other value types like int or double for example.
如果 string 的默认值是空字符串,我就不必测试,我会觉得它与其他值类型更一致,例如 int 或 double。
Assigning the default value to a specific reference type other than null
would make it inconsistent.
将默认值分配给特定的引用类型而不是null
会使其不一致。
Additionally
Nullable<String>
would make sense.
另外
Nullable<String>
会有意义。
Nullable<T>
works with the value types. Of note is the fact that Nullable
was not introduced on the original .NET platformso there would have been a lot of broken code had they changed that rule.(Courtesy @jcolebrand)
Nullable<T>
适用于值类型。值得注意的是,Nullable
原始.NET 平台上没有引入这一事实,因此如果他们更改了该规则,将会有很多损坏的代码。(礼貌@jcolebrand)
回答by Henk Holterman
Because a string variable is a reference, not an instance.
因为字符串变量是一个引用,而不是一个实例。
Initializing it to Empty by default would have been possible but it would have introduced a lot of inconsistencies all over the board.
默认情况下将其初始化为 Empty 是可能的,但它会在整个板上引入很多不一致。
回答by Soner G?nül
Why the designers of C# chose to use null as the default value of strings?
为什么 C# 的设计者选择使用 null 作为字符串的默认值?
Because strings are reference types, reference types are default value is null
. Variables of reference types store references to the actual data.
因为字符串是引用类型,所以引用类型的默认值是null
。引用类型的变量存储对实际数据的引用。
Let's use default
keyword for this case;
让我们default
在这种情况下使用关键字;
string str = default(string);
str
is a string
, so it is a reference type, so default value is null
.
str
是 a string
,所以它是一个引用类型,所以默认值为null
.
int str = (default)(int);
str
is an int
, so it is a value type, so default value is zero
.
str
是一个int
,所以它是一个值类型,所以默认值是zero
。
回答by Dave Markle
Habib is right -- because string
is a reference type.
Habib 是对的——因为它string
是一个引用类型。
But more importantly, you don'thave to check for null
each time you use it. You probably should throw a ArgumentNullException
if someone passes your function a null
reference, though.
但更重要的是,您不必null
每次使用它时都进行检查。不过,ArgumentNullException
如果有人向您的函数传递了一个null
引用,您可能应该抛出一个。
Here's the thing -- the framework would throw a NullReferenceException
for you anyway if you tried to call .ToUpper()
on a string. Remember that this case still can happen even if you test your arguments for null
since any property or method on the objects passed to your function as parameters may evaluate to null
.
事情就是这样——NullReferenceException
如果你试图调用.ToUpper()
一个字符串,框架无论如何都会为你抛出一个。请记住,即使您测试参数 for ,这种情况仍然可能发生,null
因为作为参数传递给函数的对象上的任何属性或方法都可能计算为null
。
That being said, checking for empty strings or nulls is a common thing to do, so they provide String.IsNullOrEmpty()
and String.IsNullOrWhiteSpace()
for just this purpose.
话虽如此,检查空字符串或空值是很常见的事情,因此它们提供String.IsNullOrEmpty()
并且String.IsNullOrWhiteSpace()
仅用于此目的。
回答by Tim Schmelter
You could write an extension method(for what it's worth):
您可以编写一个扩展方法(对于它的价值):
public static string EmptyNull(this string str)
{
return str ?? "";
}
Now this works safely:
现在这可以安全地工作:
string str = null;
string upper = str.EmptyNull().ToUpper();
回答by Nerrve
Empty strings and nulls are fundamentally different. A null is an absence of a value and an empty string is a value that is empty.
空字符串和空值是根本不同的。null 是没有值,空字符串是空值。
The programming language making assumptions about the "value" of a variable, in this case an empty string, will be as good as initiazing the string with any other value that will not cause a null reference problem.
编程语言对变量的“值”做出假设,在这种情况下为空字符串,与使用不会导致空引用问题的任何其他值初始化字符串一样好。
Also, if you pass the handle to that string variable to other parts of the application, then that code will have no ways of validating whether you have intentionally passed a blank value or you have forgotten to populate the value of that variable.
此外,如果您将该字符串变量的句柄传递给应用程序的其他部分,那么该代码将无法验证您是否有意传递了一个空白值,或者您是否忘记填充该变量的值。
Another occasion where this would be a problem is when the string is a return value from some function. Since string is a reference type and can technically have a value as null and empty both, therefore the function can also technically return a null or empty (there is nothing to stop it from doing so). Now, since there are 2 notions of the "absence of a value", i.e an empty string and a null, all the code that consumes this function will have to do 2 checks. One for empty and the other for null.
另一个出现问题的情况是字符串是某个函数的返回值。由于 string 是一种引用类型,并且在技术上可以同时具有 null 和空值,因此该函数在技术上也可以返回 null 或空(没有什么可以阻止它这样做)。现在,由于“缺少值”有 2 个概念,即空字符串和 null,所有使用此函数的代码都必须进行 2 次检查。一个为空,另一个为空。
In short, its always good to have only 1 representation for a single state. For a broader discussion on empty and nulls, see the links below.
简而言之,单个状态只有 1 个表示总是好的。有关空值和空值的更广泛讨论,请参阅下面的链接。
https://softwareengineering.stackexchange.com/questions/32578/sql-empty-string-vs-null-value
https://softwareengineering.stackexchange.com/questions/32578/sql-empty-string-vs-null-value
回答by Alessandro Da Rugna
Maybe the string
keyword confused you, as it looks exactly like any other value typedeclaration, but it is actually an alias to System.String
as explained in this question.
Also the dark blue color in Visual Studio and the lowercase first letter may mislead into thinking it is a struct
.
也许string
关键字让您感到困惑,因为它看起来与任何其他值类型声明完全一样,但实际上它是一个别名,System.String
如本问题中所述。
此外,Visual Studio 中的深蓝色和小写首字母可能会误导人们认为它是struct
.
回答by Dan Burton
If the default value of
string
were the empty string, I would not have to test
如果的默认值
string
是空字符串,我就不必测试
Wrong! Changing the default value doesn't change the fact that it's a reference type and someone can still explicitly setthe reference to be null
.
错误的!更改默认值不会改变它是引用类型的事实,并且有人仍然可以将引用显式设置为null
.
Additionally
Nullable<String>
would make sense.
另外
Nullable<String>
会有意义。
True point. It would make more sense to not allow null
for any reference types, instead requiring Nullable<TheRefType>
for that feature.
真点。不允许null
使用任何引用类型,而是需要Nullable<TheRefType>
该功能会更有意义。
So why did the designers of C# choose to use
null
as the default value of strings?
那么为什么 C# 的设计者选择使用
null
作为字符串的默认值呢?
Consistency with other reference types. Now, why allow null
in reference types at all? Probably so that it feels like C, even though this is a questionable design decision in a language that also provides Nullable
.
与其他引用类型的一致性。现在,为什么完全允许null
引用类型?可能是因为它感觉像 C 语言,尽管在一种还提供Nullable
.
回答by supercat
The fundamental reason/problem is that the designers of the CLS specification (which defines how languages interact with .net) did not define a means by which class members could specify that they must be called directly, rather than via callvirt
, without the caller performing a null-reference check; nor did it provide a meany of defining structures which would not be subject to "normal" boxing.
根本原因/问题是 CLS 规范(定义语言如何与 .net 交互)的设计者没有定义一种方法,通过该方法类成员可以指定必须直接调用它们,而不是 via callvirt
,调用者无需执行空引用检查;它也没有提供一种定义不受“正常”装箱影响的结构的方法。
Had the CLS specification defined such a means, then it would be possible for .net to consistently follow the lead established by the Common Object Model (COM), under which a null string reference was considered semantically equivalent to an empty string, and for other user-defined immutable class types which are supposed to have value semantics to likewise define default values. Essentially, what would happen would be for each member of String
, e.g. Length
to be written as something like [InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
. This approach would have offered very nice semantics for things which should behave like values, but because of implementation issues need to be stored on the heap. The biggest difficulty with this approach is that the semantics of conversion between such types and Object
could get a little murky.
如果 CLS 规范定义了这样一种方法,那么 .net 就有可能始终遵循公共对象模型 (COM) 建立的引导,在该模型下,空字符串引用被认为在语义上等同于空字符串,而对于其他用户定义的不可变类类型应该具有值语义来同样定义默认值。本质上,对于 的每个成员会发生什么String
,例如Length
被写成类似[InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
. 这种方法可以为应该表现得像值的事物提供非常好的语义,但由于实现问题需要存储在堆上。这种方法的最大困难是这些类型之间转换的语义Object
可能会变得有点模糊。
An alternative approach would have been to allow the definition of special structure types which did not inherit from Object
but instead had custom boxing and unboxing operations (which would convert to/from some other class type). Under such an approach, there would be a class type NullableString
which behaves as string does now, and a custom-boxed struct type String
, which would hold a single private field Value
of type String
. Attempting to convert a String
to NullableString
or Object
would return Value
if non-null, or String.Empty
if null. Attempting to cast to String
, a non-null reference to a NullableString
instance would store the reference in Value
(perhaps storing null if the length was zero); casting any other reference would throw an exception.
另一种方法是允许定义不继承自Object
但具有自定义装箱和拆箱操作(将转换为/从其他类类型)的特殊结构类型。在这种方法下,将有一个类类型NullableString
,它的行为与 string 现在一样,还有一个自定义装箱的 struct type String
,它将保存一个Value
type 的私有字段String
。尝试将 a 转换String
为NullableString
orObject
将Value
在非空或String.Empty
空时返回。尝试强制转换为String
,对NullableString
实例的非空引用会将引用Value
存储在(如果长度为零,则可能存储空值);转换任何其他引用都会引发异常。
Even though strings have to be stored on the heap, there is conceptually no reason why they shouldn't behavelike value types that have a non-null default value. Having them be stored as a "normal" structure which held a reference would have been efficient for code that used them as type "string", but would have added an extra layer of indirection and inefficiency when casting to "object". While I don't foresee .net adding either of the above features at this late date, perhaps designers of future frameworks might consider including them.
尽管字符串必须存储在堆上,但从概念上讲,它们不应该表现得像具有非空默认值的值类型。将它们存储为包含引用的“正常”结构对于将它们用作“字符串”类型的代码来说是有效的,但是在转换为“对象”时会增加额外的间接层和低效率。虽然我不认为 .net 会在这么晚的时候添加上述任何一个功能,但未来框架的设计者可能会考虑包括它们。
回答by djv
A String is an immutable object which means when given a value, the old value doesn't get wiped out of memory, but remains in the old location, and the new value is put in a new location. So if the default value of String a
was String.Empty
, it would waste the String.Empty
block in memory when it was given its first value.
String 是一个不可变对象,这意味着当给定一个值时,旧值不会从内存中消失,而是保留在旧位置,而新值则放在新位置。所以如果默认值为String a
was String.Empty
,String.Empty
当它被赋予第一个值时,它会浪费内存中的块。
Although it seems minuscule, it could turn into a problem when initializing a large array of strings with default values of String.Empty
. Of course, you could always use the mutable StringBuilder
class if this was going to be a problem.
尽管它看起来微不足道,但在使用默认值String.Empty
. 当然,StringBuilder
如果这会成为一个问题,您总是可以使用可变类。