C# 合并运算符抛出

Posted

技术标签:

【中文标题】C# 合并运算符抛出【英文标题】:C# coalesce operator Throws 【发布时间】:2012-04-12 04:38:45 【问题描述】:

我有一个带有字符串属性的类。我在读取它时使用了 coalesce 运算符,因为它可能为 null,但它仍然会抛出 NullRefrenceExeption。

string name = user.Section.ParentSection.Name ?? string.Empty;

更具体地说,它的“.ParentSection”是空的,是不是因为它甚至没有“.name”?如果是这种情况,我应该先用 if 块测试“.ParentSection”吗?

我认为 Coalesce 操作员有一些我不明白的地方,希望有人能解释一下这里出了什么问题。

【问题讨论】:

msdn.microsoft.com/en-us/library/ms173224.aspx 正如答案所暗示的那样,空合并运算符不会在这里抛出;引发异常的是对其左操作数的求值。 【参考方案1】:

更具体地说,它的“.ParentSection”是空的,所以它也是 因为它甚至没有“.name”?

是的。

如果是这种情况,我应该先用 if 测试“.ParentSection” 屏蔽?

是的。

【讨论】:

这就是我的假设,但我坚持认为这可能是一个更优雅的解决方案。谢谢:) 有一个更优雅的解决方案,叫做 Maybe Monad。看我的回答。【参考方案2】:

您需要检查 SectionParentSection 是否为空。您可以为此使用 if 语句或编写如下扩展方法:

public static class MaybeMonad

    public static TOut With<TIn, TOut>(this TIn input, Func<TIn, TOut> evaluator)
        where TIn : class
        where TOut : class
    
        if (input == null)
        
            return null;
        
        else
        
            return evaluator(input);
        
    

你会像这样使用这个方法:

string name = user.With(u => u.Section)
                  .With(s => s.ParentSection)
                  .With(p => p.Name) ?? string.Empty;

我认为它比包含大量 &amp;&amp; 的 if 语句要干净得多。

进一步阅读:http://www.codeproject.com/Articles/109026/Chained-null-checks-and-the-Maybe-monad

【讨论】:

谢谢,我去看看。【参考方案3】:

您需要先检查useruser.Sectionuser.Section.ParentSection 是否为空,然后才能对user.Section.ParentSection 的属性使用空合并运算符。

【讨论】:

【参考方案4】:

如果访问的任何对象是null,则嵌套属性访问是不安全的,这将引发NullReferenceException。您必须显式测试外部对象是否不为空。

例如:

string name = string.Empty;
if(user!=null && user.Section!=null && user.Section.ParentSection !=null)
   name = user.Section.ParentSection.Name ?? string.Empty;

一般来说,我会尽量避免嵌套访问属性,你违反了Law of Demeter。一些重构可能首先使这变得不必要。

【讨论】:

我同意; public String getParentSectionName() 我敢肯定,这将是一个受欢迎的变化。【参考方案5】:

?? 运算符检查左侧是否为空,如果是则返回右侧,如果不是左侧。 在您的情况下,左侧是对象 user.Section.ParentSection 中的“名称”属性,这是 null。

在这些情况下,要么考虑可能为 null 的内容,要么执行以下操作:

string name = user == null 
              || user.Section == null 
              || user.ParentSection == null 
              || user.Section.ParentSection.Name == null 
                 ? string.Empty 
                 : user.Section.ParentSection.Name;

(是的,我知道它很丑)

【讨论】:

【参考方案6】:

useruser.Sectionuser.Section.ParentSection 可能为空值。

?? 运算符不会阻止以下检查:

if (user != null && user.Section != null && user.Section.ParentSection != null)

确保字符串属性之前的所有内容都有效且存在,然后您可以使用??。无论您尝试多少次,都无法拨打(null).Name

【讨论】:

【参考方案7】:

是的,您需要在检查 Name 之前检查 SectionParentSection 是否为空

【讨论】:

【参考方案8】:

最好这样做:

if(user!=null && user.Section!=null && user.Section.ParentSection!=null)

     string name = user.Section.ParentSection.Name ?? string.Empty;

【讨论】:

【参考方案9】:

空合并运算符采用如下语句:

a = b ?? c;  

这说的是“评估 b;如果它有一个非空值,则将其分配给 a。否则将 c 的值分配给 a”。

但是,在 your b 中,您使用的用户对象可能为 null,其 section 对象可能为 null,其父 section 属性可能为 null,其 name 属性为可能为空。如果您想检查所有这些(通常您应该),那么您可以执行以下操作:

string name = string.Empty;  
if (user != null &&  
     user.Section != null &&  
     user.Section.ParentSection != null)  
  
  name = user.Section.ParentSection.Name ?? string.Empty;  

一旦 IF 检查失败,它将不会进一步检查,因此当您假设对象存在并尝试访问其属性之一时,您不会收到 NullReferenceException。

【讨论】:

以上是关于C# 合并运算符抛出的主要内容,如果未能解决你的问题,请参考以下文章

来自'??' 的 C# 类型推断(“var”)赋值空合并运算符

PHP 中 C# 的空值合并运算符 (??)

C# 的可空合并运算符(??)到底是怎样的宝宝?

C# 合并运算符不会替换 null 方法返回值?

是否有 C# 空合并运算符的 Python 等效项?

c#:为啥当我尝试在模拟中使用合并运算符时它不起作用