【问题标题】:How come this code is valid C# code? [duplicate]为什么这段代码是有效的 C# 代码? [复制]
【发布时间】:2012-11-04 06:35:15
【问题描述】:

可能重复:
C#: Why is adding null to a string legal?

这是有效的 C# 代码:

var samsung= "xyz" + null + null + null + null + "890";  // xyz890

这是无效的 C# 代码:

var iphone= null.ToString(); // compiler error

为什么第一个语句有效,第二个语句无效?

【问题讨论】:

  • 你不能改变nothing(这里是null)
  • 想知道编译器是否删除了空添加?有人知道吗?
  • @GrantH。如果它们是空常量,那么是的。事实上整个表达式在 IL 中被简化为"xyz890"
  • @GrantH。它们是,但从技术上讲,它不会改变结果,只会改变性能。如果它在编译时没有将它评估为单个常量(你可以简单地改变它以防止它能够做到这一点)那么它仍然可以工作,如果它不能在运行时运行它那么它不会'无法在编译时对其进行优化。换句话说,编译时优化并没有改变为什么它起作用或不起作用的解释。

标签: c# .net string null concatenation


【解决方案1】:

+ 运算符用于连接字符串,由于null 是字符串类的一个实例,它可以用作运算符的参数。 "xyz" + null 最终返回字符串“xyz”,所以这个过程只是重复,直到你真正添加"890"

虽然 null 可以用作方法参数的字符串对象,但您实际上不能在其上调用方法,因为没有任何东西可以处理方法调用。

将方法视为对象处理外部请求的一种方式,事情就更有意义了。您可以使用null 向对象发送请求作为处理内容的参数,但实际上您不能要求null 处理某些内容。

【讨论】:

  • 这也是很好的解释。谢谢!
  • "null 是字符串类的一个实例..." 不,无论如何它都不是一个实例。它是一个表达式,在某些情况下可以解释为类型为string。在这种情况下,您也可以将其解释为(object)null;结果是一样的。但是空引用不是实例,它是缺少实例。
【解决方案2】:

使用第一行,您正在连接字符串。 null 什么都不是,所以基本上你得到的是xyz890。这就像在做1+0+0+0+4 但是你的第二个,你在null 上调用ToString()null 什么都不是,所以没有什么可以打电话给ToString()。您正在尝试在未初始化的变量上调用方法。

【讨论】:

  • 哦,现在对我来说很有意义!非常感谢你们 :-) 我的问题得到了解答。
  • @user1688826 如果您的问题得到解答,您应该接受答案
  • 虽然这没有错,但您实际上并没有解释为什么可以使用 operator + 将 null 与字符串连接起来,您只是说 那个 可以。运行他的代码已经告诉了他很多......
  • @Servy:我以1+0+0+0+4为例。希望是这个概念会被理解。
  • @TyrionLannister 概念在这里无关紧要。从逻辑上讲,与“abc”连接的 null 可能是 abc,但请注意 null.Concat("abc") 会导致空指针异常。与null + "abc" 有什么不同,null + "abc" 按预期工作而没有错误?这就是您的答案应该解释的内容以实际回答问题。同样,这并没有错,它只是跳过了问题中真正重要的部分。
【解决方案3】:

由于string 是引用类型,null 可以隐式转换为string。在第一种情况下,+ 运算符的序列只是转换为String.Concat(obj1, obj2, obj3, ...)

要编译你的代码,你可以调用Convert.ToString:

var iphone = Convert.ToString(null);

【讨论】:

    【解决方案4】:

    您可以将+ 运算符视为一个全局静态函数,如下所示:

    +(string leftHandSide, string rightHandSide) {
      if (leftHandSide == null)
         leftHandSide = string.Empty;
      if (rightHandSide == null)
         rightHandSide = string.Empty;
      string returnValue;
    
      // concatenate string
    
      return returnValue;
    }
    

    由于这个字符串连接方法是静态的,它不需要实例来调用它,它处理空值。但是,当您尝试在 null 上调用 ToString 时,没有对象的实例,因此没有要调用的 ToString 方法,因此出现异常。

    【讨论】:

      【解决方案5】:

      C# 编译器将连接中的 null 视为空字符串。

       var samsung= "xyz" + null + null + null + null + "890";
      

      等于

       var samsung= "xyz" + ""+ ""+ ""+ ""+ "890";
      

      当您尝试调用null.toString() 时,您实际上是在尝试调用空对象上的方法,该方法(如果已编译)总是会导致NullReferenceException

      【讨论】:

        【解决方案6】:

        这是设计使然。你可以阅读C# Language Specification。引用:

        字符串连接:

        string operator +(string x, string y);
        string operator +(string x, object y);
        string operator +(object x, string y);
        

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

        [...]

        因此,正如其他人所说,将+ 视为一种接受两个参数的方法,并且可以将其中一个或两个都设置为null

        【讨论】:

          【解决方案7】:

          + 运算符将被转换为一个看起来很像的静态函数:

          public static string Concat(string first, string second) {...}
          

          将 null 作为参数传递给函数不是问题;它通过就好了。该函数碰巧在连接参数之前检查两个参数是否为空;如果任何参数为空,则将它们视为空字符串,以免导致异常。这里的关键点是字符串的实例成员在此函数第一次检查为空之前不会被调用。

          至于null.ToString() 在编译时对任何计算结果为null 的东西调用实例函数会导致异常。这就是这种情况的定义。

          【讨论】:

          • 很好的解释。只是一个技术细节:写作null.ToString() 给出编译时错误:CS0023: Operator '.'不能应用于 '' 类型的操作数 但是,如果你对类型有一点帮助,就像在 ((string)null).ToString() 中一样,它会编译得很好,你会得到你的 NullReferenceException 运行时。跨度>
          【解决方案8】:

          因为在任何情况下你都不能在 null 引用上调用方法,所以编译器不允许这样做。在第一种情况下,编译器会预编译字符串常量为"xyz890",所以这是一个合法的赋值。

          通常,string+ 运算符编译为支持 null 参数的 String.Concat(s1, s2, ...)

          在第二种情况下更准确地说,实际问题不是它是一个空指针,而是没有 type 可以将方法绑定到。正如在其他 cmets 中指出的那样,您可以将 null 转换为任何引用类型,并且它编译得很好:

          ((string)null).ToString();   // compiles, but fails at run-time.
          

          【讨论】:

            【解决方案9】:

            如果您查看 IL,您会发现编译器足够聪明,可以删除空值并创建连接字符串。如前所述,您不能执行 null.ToString();您可以执行 string.Empty 或将字符串分配为空。

            .method private hidebysig static void  Main() cil managed
            {
              .entrypoint
              // Code size       8 (0x8)
              .maxstack  1
              .locals init ([0] string samsung)
              IL_0000:  nop
              IL_0001:  ldstr      "xyz890"        //null has been removed by compiler.  
              IL_0006:  stloc.0
              IL_0007:  ret
            } // end of method Program::Main 
            

            编辑
            扩展尼尔森的评论。由于 null 表示 nil 引用,因此可以公平地说处理字符串 concat 的方式是 C# 允许的操作。我想它使用字节数组构建,它会省略空值,因此只是让它看起来好像它正在连接空值。

            【讨论】:

            • 我认为原始海报是在问为什么它是合法的。这是一个技术细节,编译器自己compile-time执行完整的操作(五个加号),并且只在其IL输出中发出正确的“sum”。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-02-02
            • 2012-12-03
            • 2017-04-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多