为什么stringtypes的默认值是null而不是空string?
在我可以安全地应用ToUpper()
, StartWith()
等方法之前,testing我的所有string为null
是非常烦人的。
如果string
的默认值是空string,我不需要testing,我会觉得它是更一致的其他值types,如int
或double
例如。 此外, Nullable<String>
将是有意义的。
那么为什么C#的devise者select使用null
作为string的默认值呢?
注意:这涉及到这个问题 ,但更关注为什么而不是如何处理它。
为什么stringtypes的默认值是null而不是空string?
因为string
是引用types ,所有引用types的默认值为null
。
在我可以安全地应用ToUpper(),StartWith()等方法之前,testing我的所有string为null是非常烦人的。
这与参考types的行为一致。 在调用它们的实例成员之前,应该先检查一个空引用。
如果string的默认值是空string,我不需要testing,我会觉得它是更一致的其他值types,如int或double例如。
将默认值分配给非null
的特定引用types会使其不一致 。
此外,
Nullable<String>
将是有意义的。
Nullable<T>
与值types一起使用。 值得注意的是Nullable
并没有在原来的.NET平台上引入,所以如果他们改变了这个规则,就会出现很多破坏的代码( Courtesy @jcolebrand )
Habib是正确的 – 因为string
是一个引用types。
但更重要的是,每次使用时都不必检查null
。 不过,如果有人将你的函数传递给null
引用,你可能应该抛出一个ArgumentNullException
。
这是事情 – 如果您尝试在string上调用.ToUpper()
,框架将为您抛出NullReferenceException
。 记住即使你testing你的参数为null
也会发生这种情况,因为作为parameter passing给你的函数的对象上的任何属性或方法可能评估为null
。
这就是说,检查空string或空值是一个常见的事情,所以他们提供String.IsNullOrEmpty()
和String.IsNullOrWhiteSpace()
正是为了这个目的。
你可以写一个扩展方法 (值得):
public static string EmptyNull(this string str) { return str ?? ""; }
现在这个工作安全:
string str = null; string upper = str.EmptyNull().ToUpper();
空string和空值是根本不同的。 null是缺less值,空string是空的值。
编程语言对variables的“值”(在这种情况下为空string)做出假设,就像使用任何其他不会导致空引用问题的值来初始化string一样好。
另外,如果将句柄传递给应用程序的其他部分,则该代码将无法validation是否有意传递了空值,或者忘记填充该variables的值。
另外一个问题是当string是某个函数的返回值时。 由于string是一个引用types,并且在技术上可以有一个值为null和empty,因此该函数也可以在技术上返回null或empty(这样做没有任何阻止)。 现在,由于有2个“缺less值”的概念,即一个空string和一个空值,所有使用这个函数的代码将不得不做2次检查。 一个是空的,另一个是空的。
总之,它总是有一个单一的状态只有一个代表。 有关空白和空值的更广泛讨论,请参阅下面的链接。
https://softwareengineering.stackexchange.com/questions/32578/sql-empty-string-vs-null-value
处理用户input时为空vs空
我知道我对这里的派对有点晚了,但是如果有人碰到这个,你也可以(从VS2015和新的编译器开始)使用以下
string myString = null; string result = myString?.ToUpper();
string结果将为空。
因为一个stringvariables是一个引用 ,而不是一个实例 。
默认情况下将其初始化为空将是可能的,但是会引起很多不一致的情况。
为什么C#的devise者select使用null作为string的默认值?
由于string是引用types ,引用types是默认值为null
。 引用types的variables存储对实际数据的引用。
我们在这个案例中使用default
关键字;
string str = default(string);
str
是一个string
,所以它是一个引用types ,所以默认值是null
。
int str = (default)(int);
str
是一个int
,所以它是一个值types ,所以默认值是zero
。
根本原因/问题是CLS规范(定义语言如何与.net交互)的devise者没有定义类成员可以指定它们必须直接调用的方式,而不是通过callvirt
,没有调用者执行空引用检查; 也没有提供一个不受“正常”拳击限制的结构。
如果CLS规范定义了这样的一种方法,那么.net将可能始终如一地遵循由公共对象模型(COM)build立的领导,在这个领导下空string引用被认为在语义上等同于一个空string,用户定义的不可变类types应该具有值语义来同样定义默认值。 从本质上讲,会发生什么会是每个成员的String
,例如Length
被写为像[InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
[InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
。 这种方法将提供非常好的语义,它应该像值一样行事,但是由于实现问题需要存储在堆上。 这种方法最大的困难在于这种types和Object
之间的转换的语义会变得有些模糊。
另一种方法是允许定义不是从Object
inheritance的特殊结构types,而是具有自定义装箱和拆箱操作(可以转换为其他类types)。 在这种方法下,将会有一个types为NullableString
行为像现在的string,以及一个定制的结构typesString
,它将保存一个String
types的私有字段Value
。 尝试将String
转换为NullableString
或Object
,如果为非null,则返回Value
如果为null,则返回String.Empty
。 尝试转换为String
,对NullableString
实例的非null引用将在Value
存储引用(如果长度为零,则可能会存储null); 铸造任何其他的引用会抛出一个exception。
尽pipestring必须存储在堆上,但是概念上没有理由不应该像具有非空默认值的值types那样工作。 把它们作为一个“普通”结构来存储,对于使用它们作为types“string”的代码来说,它是有效的,但是在向“对象”投射时会增加一个额外的间接层和低效率层。 虽然我没有预见到.net在这个迟到的日子里添加了上述任何一个特性,但是未来的框架devise者可能会考虑包含它们。
如果
string
的默认值是空string,我不必testing
错误! 更改默认值不会改变它是引用types的事实,而且某人仍然可以显式地将引用设置为null
。
此外,
Nullable<String>
将是有意义的。
真的。 对于任何引用types,不允许为null
,而是需要Nullable<TheRefType>
。
那么为什么C#的devise者select使用
null
作为string的默认值呢?
与其他参考types一致。 现在,为什么允许引用types为null
? 大概是这样的感觉就像C,尽pipe这是一个有问题的devise决定,它也提供了Nullable
语言。
一个string是一个不可变的对象,这意味着当给定一个值时,旧值不会从内存中消失,而是保留在原来的位置,并将新值置于新的位置。 所以如果String a
的默认值是String.Empty
,那么当它被赋予第一个值的时候,会浪费内存中的String.Empty
块。
虽然它看起来很小,但在使用String.Empty
默认值初始化大量string时,可能会变成问题。 当然,如果这将是一个问题,你总是可以使用可变的StringBuilder
类。
由于string是引用types,引用types的默认值为空。
也许如果你使用??
运算符时分配你的stringvariables,它可能会帮助你。
string str = SomeMethodThatReturnsaString() ?? ""; // if SomeMethodThatReturnsaString() returns a null value, "" is assigned to str.
也许string
关键字混淆了你,因为它看起来和任何其他的值types声明完全一样,但是它实际上是System.String
一个别名,正如在这个问题中所解释的那样。
此外,在Visual Studio中的深蓝色和小写的第一个字母可能会误认为它是一个struct
。
可空types直到2.0才进入。
如果在该语言的开头已经创build了可为空的types,那么string将是不可空的并且是string的? 本来是可以空的。 但是他们无法做到这一点来向后兼容。
很多人都在谈论ref-type或not reftypes,但是string是一个不寻常的类,解决scheme已经被发现使它成为可能。
我正在做如下
class myPOCOClass { private string _item1=""; public string item1 { get { return (_item1==null?"":_item1); } set{ _item1=value; } } }