【问题标题】:Possible Null Reference Exception using "as" operator使用“as”运算符可能出现空引用异常
【发布时间】:2013-08-09 14:55:24
【问题描述】:

在以下代码中:

MyObject objInstance;

private void someEventHandler(object sender, EventArgs e)
{
    if (sender == objInstance && (sender as MyObject).SomeBoolProperty)
        // Do Something
}

Resharper 警告 sender as MyObject 可能是 NullReferenceException。鉴于此代码,这可能吗?我假设如果sender == objInstance (sender as MyObject) 不会返回 null,但这不是 Resharper 消息第一次通知我我不知道的 C# 行为/功能。

【问题讨论】:

  • 既然你已经建立了它们的相等性,为什么不直接使用objInstance 而不是(sender as MyObject)
  • 已经进行了更改,因为if 正文使用的是objInstance,我不喜欢那些曲折的线条。我对造成它们的原因更感兴趣。
  • 如果 objInstance 为 null,sender == objInstance 可以返回 true,即使它为 null。这将导致条件语句的下一部分抛出 NullReferenceException。

标签: c# resharper nullreferenceexception


【解决方案1】:

当您使用as 时,如果无法转换对象(在本例中为MyObject),则返回null。因此,您的(sender as MyObject) 行有可能为空。

【讨论】:

  • 没错,但我的问题是关于这个特定情况,我们知道sender 等于MyObjectas 操作之前的特定实例
  • @HarrisonPaine - 但我们不知道sender 是否等于特定实例,因为sender 可以为空,objInstance 也可以为空,因此不会短路if 检查。然后在访问SomeBoolProperty 时会抛出NullReferenceException
  • 另外,resharper 会给你这个错误,因为理论上你可以将该事件处理程序分配给其他一些不会发送 MyObject 作为发送者的元素。所以这是一条有效的消息,但是否要忽略它取决于您。您的第一个 if 条件可能为假。
【解决方案2】:

这段代码肯定会导致NullReferenceException 被抛出。考虑objInstancesender 的值为null 的情况。在这种情况下,sender == objInstance 将是 true,因为 null == null 和因此 sender as MyObject 也将返回 null 并且代码将抛出属性访问

编写该代码的最佳方式是

var senderObj = sender as MyObject;
if (senderObj != null && 
    senderObj == objInstance && 
    senderObj.SomeBoolProperty) { 
  // Do something
}

很遗憾,我不相信有办法显着简化此代码。您试图表达 3 个特定的不相关条件。因此,它们都必须进行测试

【讨论】:

  • 非常正确。错过了细微差别。
  • 发件人可以为空吗?我想如果在引发事件后将引用设置为 null 可以吗? - 实际上,我想不能保证发件人实际上是发件人。我已将 sender 作为 null 发送给自己之前的事件...
  • @Michael 绝对可以是null。事件模式只使用委托,您可以将 null 传递给委托就好了。一般来说它不会是null,但这并不意味着它不能是:)
【解决方案3】:

在这种情况下,您知道发件人实际上是MyObject。所以用一个简单的演员代替as

if (sender == objInstance && ((MyObject)sender).SomeBoolProperty)

或者,甚至更好:

if (sender == objInstance && objInstance.SomeBoolProperty)

【讨论】:

    【解决方案4】:

    如果您的强制转换无效,as 运算符将返回 null。如果 Event sender 不是 MyObject 的,(sender as MyObject) == null。

    如果 objInstance 保证不为 null,那么您的语句将永远不会抛出 NullReferenceException。但是,如果 objInstance 为 null,它可能会抛出。

    既然可以确定 sender == objInstance,那么在验证 objInstance != null 之后,只需对 objInstance 进行操作,而不是强制转换 sender。

    【讨论】:

      【解决方案5】:

      这是因为 R# 并不总是最聪明的。此外,如果senderobjInstance 都是null,您仍然可以获得NullReferenceException。无论如何,既然你已经建立了他们的平等,为什么不直接使用objInstance

      试试这个:

      if (sender == objInstance && objInstance.SomeBoolProperty)
      

      【讨论】:

        【解决方案6】:

        摆脱波浪:

        MyObject objInstance;
        
        private void someEventHandler(object sender, EventArgs e)
        {
            var myObj = sender as MyObject;
        
            Debug.Assert(myObj != null);
        
            if (sender == objInstance && myObj .SomeBoolProperty)
                // Do Something
        }
        

        R# 理解断言并将停止警告您。此外,随意插入这些调试断言也不是什么坏习惯。每当您收到引用类型作为public 方法的参数时,我会断言该值不为空,或者在某些情况下抛出一个专门用于接收空参数的异常,而不是等待代码进一步失败.当该 null 被传递给其他方法时,情况会变得更糟,这使得很难知道代码在何时何地会失败。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-23
          • 1970-01-01
          • 2014-02-07
          • 2023-01-25
          • 2015-09-12
          • 2010-12-18
          • 2019-10-19
          相关资源
          最近更新 更多