Mar*_*cel 207 c# string default-value
这是很烦人的测试我所有的字符串null之前,我可以放心地运用类似的方法ToUpper(),StartWith()等...
如果默认值string是空字符串,我就不用考了,我会觉得它是与其他价值类型,如更一致int或double为例子.另外Nullable<String>有意义.
那么为什么C#的设计者选择使用null字符串的默认值呢?
注意:这与此问题有关,但更侧重于为什么而不是如何处理它.
Hab*_*bib 299
为什么字符串的默认值为null而不是空字符串?
因为string是引用类型,所有引用类型的默认值是null.
在我可以安全地应用ToUpper(),StartWith()等方法之前,测试我的所有字符串是非常烦人的...
这与引用类型的行为一致.在调用实例成员之前,应该对空引用进行检查.
如果string的默认值是空字符串,我就不必测试了,我觉得它与其他值类型(例如int或double)更加一致.
将默认值分配给特定引用类型而不是null使其不一致.
另外
Nullable<String>有意义.
Nullable<T>使用值类型.值得注意的是,Nullable原始.NET平台上没有引入这一事实,因此如果他们改变了这条规则,就会有很多破碎的代码.(图片来自@jcolebrand)
Dav*_*kle 39
Habib是对的 - 因为它string是一种参考类型.
但更重要的是,您不必null每次使用它都要检查.但是,ArgumentNullException如果某人将您的函数作为null参考传递,您可能应该抛出一个.
这就是事情 - NullReferenceException如果你试图调用.ToUpper()一个字符串,框架会为你抛出一个.请记住,即使您测试参数,这种情况仍然会发生,null因为传递给函数的对象上的任何属性或方法都可以作为参数进行评估null.
话虽这么说,检查空字符串或空值是常见的事情,因此它们提供String.IsNullOrEmpty()并String.IsNullOrWhiteSpace()仅用于此目的.
Tim*_*ter 23
你可以写一个扩展方法(为了它的价值):
public static string EmptyNull(this string str)
{
return str ?? "";
}
Run Code Online (Sandbox Code Playgroud)
现在这安全地工作:
string str = null;
string upper = str.EmptyNull().ToUpper();
Run Code Online (Sandbox Code Playgroud)
rus*_*ema 16
您也可以(从VS2015和新编译器开始)使用以下内容
string myString = null;
string result = myString?.ToUpper();
Run Code Online (Sandbox Code Playgroud)
字符串结果将为null.
Ner*_*rve 14
空字符串和空值根本不同.null表示缺少值,空字符串表示空值.
编程语言对变量的"值"进行假设,在本例中为空字符串,与使用任何其他不会导致空引用问题的值初始化字符串一样好.
此外,如果将句柄传递给该字符串变量到应用程序的其他部分,那么该代码将无法验证您是否故意传递了空白值,或者您忘记填充该变量的值.
另一个会出现问题的场合是字符串是某个函数的返回值.由于string是一个引用类型,并且在技术上可以将值设置为null并且两者都为空,因此该函数在技术上也可以返回null或空(没有什么可以阻止它这样做).现在,由于存在2个"缺少值"的概念,即空字符串和空值,所有使用此函数的代码都必须进行2次检查.一个用于空,另一个用于null.
简而言之,对于单个状态只有1个表示总是好的.有关empty和nulls的更广泛讨论,请参阅下面的链接.
https://softwareengineering.stackexchange.com/questions/32578/sql-empty-string-vs-null-value
根本原因/问题是CLS规范的设计者(定义语言如何与.net交互)没有定义一种方法,通过该方法,类成员可以指定必须直接调用它们,而不是通过callvirt调用,而不需要调用者执行空引用检查; 它也没有提供任何不受"正常"拳击影响的定义结构.
如果CLS规范定义了这样一种方法,那么.net就有可能始终遵循公共对象模型(COM)建立的线索,在该线索下,空字符串引用被认为在语义上等同于空字符串,而对于其他用户定义的不可变类类型,它们应具有值语义,以同样定义默认值.从本质上讲,会发生的事情将是每个成员String,例如Length写成类似的东西[InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }.这种方法可以为应该表现得像值的事物提供非常好的语义,但是由于实现问题需要存储在堆上.这种方法最大的困难在于这些类型之间转换的语义Object可能会有点模糊.
另一种方法是允许定义不继承的特殊结构类型,Object而是使用自定义装箱和拆箱操作(可以转换为/从某些其他类类型转换).在这种方法下,会有一个类型NullableString,其行为与现在的字符串一样,以及一个自定义框结构类型String,它将包含一个Value类型的私有字段String.尝试将a转换String为NullableString或Object将返回Value非null,或者String.Empty如果为null.尝试转换String为对NullableString实例的非null引用将存储引用Value(如果长度为零,则可能存储null); 转换任何其他引用将引发异常.
尽管字符串必须保存在堆上,有概念没有理由他们不应该表现得就像是有一个非空默认值的值类型.将它们存储为保持引用的"普通"结构对于将它们用作类型"字符串"的代码是有效的,但是在转换为"对象"时会增加额外的间接层和低效率.虽然我没有预见.net会在这个晚期添加上述任何一个功能,但未来框架的设计者可能会考虑将它们包括在内.
??也许如果您在分配字符串变量时使用运算符,它可能会对您有所帮助。
string str = SomeMethodThatReturnsaString() ?? "";
// if SomeMethodThatReturnsaString() returns a null value, "" is assigned to str.
Run Code Online (Sandbox Code Playgroud)
因为字符串变量是引用,而不是实例.
默认情况下将其初始化为Empty是可能的,但它会在整个板上引入很多不一致的地方.
为什么C#的设计者选择使用null作为字符串的默认值?
因为字符串是引用类型,所以引用类型是默认值null.引用类型的变量存储对实际数据的引用.
我们default在这种情况下使用关键字;
string str = default(string);
Run Code Online (Sandbox Code Playgroud)
str是a string,所以它是引用类型,所以默认值是null.
int str = (default)(int);
Run Code Online (Sandbox Code Playgroud)
str是一个int,所以它是一个值类型,所以默认值是zero.