C#添加字符串+ null不会抛出错误?

时间:2010-11-17 15:45:35

标签: c#

作为一名程序员,我本来希望这会引发异常。是否有理由将null视为“”?

string s = "hello";
string t = null;

Console.WriteLine(s + t);

输出:

  

您好

为了强调我的问题,你知道为什么决定将null转换成String.Empty ?我期待一些字符串被添加,但是有一个问题进一步回到它没有正确检索它并返回null。这个问题没有引起注意!

这是一个伪代码,为什么我认为它是坏的(为什么我发现没有错误感到震惊):

您可以假设我重载了ToString,以提供此人的姓名或有关他们的详细信息。

Person p = PersonDatabase.GetForName("Jimmy Gibbs");

Console.WriteLine("Name is: " + p.ToString());

引发异常,因为p为null

String p = PersonDatabase.GetForName("Jimmy Gibbs").Name;

Console.WriteLine("Name is: " + p);

不抛出异常,即使p为null(它将其视为“”)。

(如果你想挑剔并且说我将无法获得Name,因为GetforName将为null,请将其视为:)

String p = PersonDatabase.GetNameFromID(1234); // Returns a string or null if not found

Console.WriteLine("Name is: " + p);

(如果你在一个列表或数组中使用这个值,你最终会得到一个空白条目,这对我来说是破坏的,它创建了javascript并试图通过ID“”获取元素。

7 个答案:

答案 0 :(得分:20)

来自C# Language Specification

  

7.8.4加法算子

     

字符串连接:

     

string operator +(string x,string y);   string operator +(string x,object y);   字符串运算符+(对象x,字符串y);

     

二进制+的这些重载   运算符执行字符串连接。   如果字符串连接的操作数   为null,空字符串为   替换。否则,任何非字符串   参数转换为其字符串   通过调用虚拟表示   从类型继承的ToString方法   宾语。如果ToString返回null,则为   空字符串被替换。

答案 1 :(得分:7)

+运算符在生成的IL中以string.Concat的形式发出。

s + t = string.Concat(s, t)

并且在查看实现时,它检查参数是否为null并返回string.Empty:

用反射器拆卸:

[SecuritySafeCritical]
public static string Concat(string str0, string str1)
{
    if (IsNullOrEmpty(str0))
    {
        if (IsNullOrEmpty(str1))
        {
            return Empty;
        }
        return str1;
    }
    if (IsNullOrEmpty(str1))
    {
        return str0;
    }
    int length = str0.Length;
    string dest = FastAllocateString(length + str1.Length);
    FillStringChecked(dest, 0, str0);
    FillStringChecked(dest, length, str1);
    return dest;
}

答案 2 :(得分:1)

在字符串连接操作中,C#编译器将空字符串视为空字符串,但它不会转换原始空字符串的值。其他信息http://msdn.microsoft.com/en-us/library/aa691375(VS.71).aspx

答案 3 :(得分:1)

如果我有一个橘子并添加另一个橘子,我现在有两个橘子。

如果我有一个橙色并添加NOTHING,我仍然有橙色。

对我来说,在字符串中添加NULL并获取原始字符串似乎非常直观和语义。当在不存在的实例上访问Properties或实例方法时,应保留NullReferenceExceptions,例如。

string myString = null;
string lowerCaseString = myString.ToLower();

可以理解地抛出NullReferenceException,因为我试图访问不存在的引用上的ToLower()实例方法,因此Null 引用异常(即堆栈上有一个东西,但没有关于堆的事。)

使用NULL字符串连接操作抛出异常意味着在处理字符串时会有大量额外的防御性NULL代码检查,这很烦人。抱歉,我碰巧同意C#.NET如何处理这个问题。 Java不会这样做吗?


如果要检查字符串是否包含值,请使用String.IsNullOrEmpty(myString);String.IsNullOrWhitespace(myString);(仅限.NET 4.0)

答案 4 :(得分:1)

在考虑所做出的设计决策时,我们不仅应该关注字符串的加号运算符,还应关注相关的类和方法,例如: String.Concat(String, String)StringBuilder.Append(String)。这些类是Base Class Library的一部分,广泛用于其他语言(例如Visual Basic和F#)。

从语言和平台设计的角度来看,所有这些方法都应该在一致的派系中运行(即以相同的方式处理null)。我看到三种可能的选择:

  • 抛出异常

    这是一个“安全”的解决方案,因为它不清楚如何处理null。作为权衡,它需要更具防御性的编程风格和更冗长的代码。

  • 使用某些表示形式为null,例如<null>null[null](Java风格)

    这是您期望的结果。目前尚不清楚为什么会发生这种情况以及应该如何表示零。

  • 以与空字符串(.NET样式)相同的方式处理null

    背后的想法是null的文本表示(即缺少的对象)是一个空字符串。在这种情况下,程序员可以利用此行为并编写更短的代码。另一方面,它可以隐藏错误。

必须做出一些决定,我认为没有明显的选择。 C#和其他.NET语言中的预期行为已明确记录,并且在处理串联的所有方法中都是一致的。

答案 5 :(得分:0)

用户定义的运算符只是静态方法,当然可以接受null个参数。例如,这对代表来说非常有用。

因此,字符串接受null不是技术性的,而是设计决策。将null视为“”可能有时很有用,因为很多用户代码都将它们视为相同。

答案 6 :(得分:-2)

实际上这是字符串的表示方式....没有错。 null用作终止字符。

例如:

字符串a:“blahblah [null]” 所以无论什么读取字符串都知道停止为null。

所以当你创建一个像这样的字符串时: 字符串b:“[null]” 它完全有效。

现在,null之前没有字符。所以当你的程序开始读取字符串时,它会遇到null(完全有效)并停止....因此......空字符串!!