【问题标题】:Why does the following conditional operator "?:" compile but give a run-time error为什么以下条件运算符“?:”编译但给出运行时错误
【发布时间】:2014-07-01 08:04:53
【问题描述】:

我不知道为什么下面的程序编译时没有警告,但是在异常块中条件运算符给出了 NullReferenceException。

using System;

namespace Playground
{
    class Program
    {
        static void Main(string[] args)
        {
            string message1 = "First message.";
            string message2 = null;
            // This works without a problem
            Console.WriteLine(message1 + message2 == null ? "" : Environment.NewLine + message2);
            Console.ReadKey();

            try
            {
                throw new Exception("Now with an exception.");
            }
            catch (Exception ex)
            {
                // This will give a NullReferenceException:
                Console.WriteLine(ex.Message + ex.InnerException == null ? "" : Environment.NewLine + ex.InnerException.Message);
                // ..But this will work:
                Console.WriteLine(ex.Message + (ex.InnerException == null ? "" : Environment.NewLine + ex.InnerException.Message));
            }
        }
    }
}

我知道?? 运算符,我的问题是为什么异常处理程序中的第一行会给出 NullReferenceException。

【问题讨论】:

  • @Atomosk (Environment.NewLine + ex.InnerException.Message) 应该可以解决问题 如果ex.InnerException 为空,那么仍然会抛出异常
  • “但这会起作用:”这一行与另一行大不相同,我希望你能意识到这一点。除了ex.Message + ex.InnerException == null,因为你的情况真的没有任何意义。这里当 innerException 为 null 时为假,因为 "foo" + null = "foo"
  • 不带括号相当于'将 ex.Message 与 ex.InnerException.ToString() 连接,然后将结果与 null 进行比较'。
  • 那么为什么Console.WriteLine(message1 + message2 == null ? "" : Environment.NewLine + message2); 有效?
  • @Meine 与 null 连接是可以的,调用 null 的 Message 是异常。把Environment.NewLine + message2改成Environment.NewLine + message2.ToString()会抛出异常。

标签: c# conditional-expressions


【解决方案1】:
ex.Message + ex.InnerException

转换成

string.Concat(ex.Message, ex.InnerException);

这会检查其参数是否为 null,如果不是,则仅将它们转换为字符串。 这意味着

ex.Message + ex.InnerException == null

false 所以表达式

Environment.NewLine + ex.InnerException.Message

被评估。这会引发异常,因为 ex.InnerException 为 null。

【讨论】:

  • 只有在不是时才将它们转换为字符串。不,它不会。它为空值添加一个空字符串。
  • @Selman22 - 是的,我的意思是它不会对他们调用ToStringstring.Empty 是字符串连接的标识,所以什么都不做和连接 string.Empty 之间没有明显的区别。
  • 那么为什么Console.WriteLine(message1 + message2 == null ? "" : Environment.NewLine + message2); 有效?
  • @Meine 因为您没有尝试访问 message2 的任何成员,即使它为 null 它也只是返回一个空字符串。
  • @Meine - 问题中的代码抛出,因为您试图访问 null 对象的 Message 属性。 string.Concat 对于空参数是安全的,所以如果 message1message2 为空,message1 + message2 是安全的。如果您尝试在 else 分支中评估 message1.Length,您也会得到一个异常。
【解决方案2】:

如果InnerException 为空但ex.Message 不为空,那么第一个表达式将评估为false 并尝试访问ex.InnerException.Message,这将为您提供NullReferenceException

在第二个表达式中,您尝试访问 ex.InnerException.Message,如果 ex.InnerException 不为空,这就是它起作用的原因..

NullReferenceException 在您尝试访问 null object 的成员(方法、属性、字段等)时发生。在您的第一个示例中:

message1 + message2 == null ? "" : Environment.NewLine + message2;

您将新行与message2 连接起来,并且您没有访问message2 上的任何属性或方法。它只是为空值添加一个空字符串。看看string.Concatdocumentation

该方法连接str0和str1;它不添加任何分隔符。 空字符串用于代替任何空参数。

如果你写:

message1 + message2 == null ? "" : Environment.NewLine + message2.ToString();

然后你会得到一个异常。

【讨论】:

  • 我非常喜欢这个答案,因为它还解决了字符串示例不抛出错误的原因。但是@Lee 的示例以非常清晰的方式解决了我的问题,因此我将他的答案标记为答案。
猜你喜欢
  • 2017-04-08
  • 2012-11-04
  • 2015-12-13
  • 2014-11-05
  • 2014-12-24
  • 2013-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多