2009-08-11 148 views
4

假设我有三个类A,B和C,它们嵌套的方式使我可以通过A访问C到B(即A.B.C)。如果我试图访问C的一个简单属性,比如说Id类型int,并且我没有在A中创建B的新实例(或B中的C),我会得到一个'Object reference not set to an instance of一个东西。'错误。未将对象引用设置为对象的实例。 - DefaultValue

我想知道的是,如果有一种简单的方式说让我A.B.C.Id,并且如果你不能在某种程度上产生一个空值,那么给我一个默认值。

var myId = A.B.C.Id <some operator> -1; 

目前我正在做这样的事情,它感觉很糟糕。

var myId = A == null ? -1 : A.B == null ? -1 : A.B.C == null ? -1 : A.B.C.Id; 

回答

2

在C#中没有特别的语法可以做你想做的事情。

但是有一些架构方式,如何去做。

您可以使用Null Object Design Pattern 或可以延长A,B,C类与扩展方法,它允许空值:如果你必须去那深藏在你可能想创建一个属性

​​
+1

为什么downwote? – TcKs 2009-08-11 14:37:50

+0

我接受这个作为我的问题的答案,因为事实上TcK已经尽最大努力为我的情况提供解决方案。我在一个理想的世界里感知,我会重构并摆脱这种情况,但不幸我不在那​​里工作:)。 – voiddog 2009-08-14 09:20:35

1

查找到dependency injection这将在A B和B创建C当你答的新实例,或者只是将代码放在你的类的构造函数来创建这样的实例。 (所以在A()中创建B和在B()中创建C)

它感觉错误的原因是,正如其他人指出的那样,您不应该处于发生这种情况的情况。

+0

删除代码示例,因为它是错误的BTW – Damien 2009-08-11 13:50:05

+0

如何解决依赖注入与空值的问题? – TcKs 2009-08-11 13:53:25

+1

它不会解决ID为空的问题,但它将解决从属类(在这种情况下,B和C)为空的问题,因为它们将使用A创建。 – Damien 2009-08-11 13:58:14

4

通过经过A或B或两者都打破了Law of Demeter这是不好的做法。如果需要以某种方式引用某个东西,则需要一个空的构造函数来构建这种连接。

+0

取决于你对德米特法的解释的严格性。 'person.Name.FirstName','person.Name.LastName'是否违反了Law?我想大多数人不会那么严格。 – Ruben 2009-08-11 14:21:53

+0

我认为他意味着逻辑类。任何包含我猜想的方法的东西。我不知道有一个书面规则+1; – Damien 2009-08-11 14:27:55

+0

@Ruben德米特定律可以被打破,有时它可以打破,但如果你打破它,我会建议看看你的结构,看看你是否可以构造你的对象,这样你就不会因为你越少违反定律demeter越有可能你的代码会被测试,因为你可以将更多的依赖关系注入到它中。 – AutomatedTester 2009-08-11 14:34:48

1

在A中给你null或BCId。

+0

我会说更深入: 答:我得到{返回B == null? -1:B.I} B.I get {return C == null? -1:C.I} 但这不是一个选项,如果你有很多属性 – Toto 2009-08-12 08:42:02

-2

你可以试试这个代码:

var myId = -1; 
try 
{ 
    myId = A.B.C.Id; 
} 
catch (NullReferenceException e) 
{ 
    myId = -1; 
} 
+2

-1这是非常糟糕的方式,如何做到这一点。 它会使程序变得缓慢,如果经常会抛出异常,调试将变得更加困难。 – TcKs 2009-08-11 13:52:16

+3

使用异常来控制程序流是不好的做法。在这种情况下,您可以轻松检查空值以避免引发异常。 – 2009-08-11 13:53:27

+2

请勿将异常用作控制流。您的代码将更具可读性,并且可以维护,如果您拼写出空的检查。 – 2009-08-11 13:56:34

1

这是一个非常适合的Null Object设计模式。

基本上,定义NullB这样的:

public class NullB : B 
{ 
    public override C C 
    { 
     get { return new NullC(); } 
    } 
} 

然后正是如此定义NullC:

public class NullC : C 
{ 
    public override int Id 
    { 
     get { return 0; } 
    } 
} 

这显然需要有问题的类有虚拟成员,但它是更安全的方式。然后,当你有B和C的实例时,你只需使用并返回它们。

0

您可以使用属性来检查请求的类是否为null。如果是,它将创建该类的新实例。

class ClassA 
{ 
    private ClassB m_ClassB = null; 
    public ClassB B 
    { 
     get 
     { 
      //check if we already have an instance of the class. 
      //if not create it 
      if (m_ClassB == null) 
      { 
       m_ClassB = new ClassB(); 
      } 
      return m_ClassB; 
     } 
    } 
} 

class ClassB 
{ 
    private ClassC m_ClassC = null; 
    public ClassC C 
    { 
     get 
     { 
      //check if we already have an instance of the class. 
      //if not create it 
      if (m_ClassC == null) 
      { 
       m_ClassC = new ClassC(); 
      } 
      return m_ClassC; 
     } 
    } 
} 

class ClassC 
{ 
    private int m_Id = 123; 
    public int ID 
    { 
     get 
     { 
      return m_Id; 
     } 
    } 
} 

然后,你可以访问你所需要的是这样

CLassA A = new ClassA(); 
int id = A.B.C.ID; 
相关问题