2012-03-28 114 views
2

我有一个字符串属性的类。我在阅读时使用了coalesce操作符,因为它可能为空,但它仍会抛出一个NullRefrenceExeption。C#coalesce运算符抛出

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

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

我假设有一些关于Coalesce操作符的东西我不明白,希望有人可以对这里发生什么事情有所了解。

+0

http://msdn.microsoft.com/en-us/library/ms173224.aspx – Rawling 2012-03-28 14:50:02

+1

正如答案所暗示的那样,空合并运算符不会在这里抛出;它的左操作数的评估抛出异常。 – phoog 2012-03-28 14:56:52

回答

7

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

是的。

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

是的。

+0

多数民众赞成我所认为的,但我强硬它可能是一个更优雅的解决方案。感谢:) – 2012-03-28 14:58:34

+0

有一个更优雅的解决方案称为Maybe Monad。看到我的答案。 – FishBasketGordo 2012-03-28 15:00:24

3

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

3

如果任何访问的对象是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。首先,一些重构可能会使这不必要。

+0

我同意; '公共字符串getParentSectionName()'将是一个受欢迎的变化,我敢肯定。 – 2012-03-28 14:56:40

1

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

??运营商并不能阻止类似的检查:

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

确保一切到字符串属性是有效的存在,那么你可以使用??。不管你尝试了多少次,你都不能拨打(null).Name

2

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

在这种情况下,不是想上什么可能为空或做这样的事情:

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

(是的,它的丑陋,我知道)

0

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

0

这可能是最好做这样的事情:

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

您需要检查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; 

我觉得它比if语句更清洁了很多与很多&&

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

+0

谢谢,我会检查一下。 – 2012-03-28 15:06:40

0

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

a = b ?? c; 

它说的是“评估B;如果它有一个非空值,然后分配到否则将c的值赋给一个“。

但是内 B您正在使用的可能为null具有部分对象,可以为null有可能是空的是有一个名字属性,可以为null父部分属性的用户对象。如果您想检查所有的这些(通常你应该),那么你可以这样做:

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

只要IF检查失败也不会进一步检查,因此你没有得到一个NullReferenceException时你假定有一个对象存在,然后尝试访问它的一个属性。