C# 对象引用未设置为对象的实例。-默认值

C# 对象引用未设置为对象的实例。-默认值,c#,C#,假设我有三个类A、B和C,它们的嵌套方式是我可以通过A(即A.B.C)通过B访问C。如果我试图访问C的一个简单属性,比如Id类型int,而我还没有在a(或B中的C)中实例化新的B,我会得到一个“对象引用未设置为对象的实例”错误 我想知道的是,是否有一种简单的方式告诉我a.B.C.Id,如果你不能因为某个东西是空的,那么给我一个默认值 var myId = A.B.C.Id <some operator> -1; 当你创建一个新的A实例时,看看哪个会在B中创建C,哪个会在A中创建B。

假设我有三个类A、B和C,它们的嵌套方式是我可以通过A(即A.B.C)通过B访问C。如果我试图访问C的一个简单属性,比如Id类型int,而我还没有在a(或B中的C)中实例化新的B,我会得到一个“对象引用未设置为对象的实例”错误

我想知道的是,是否有一种简单的方式告诉我a.B.C.Id,如果你不能因为某个东西是空的,那么给我一个默认值

var myId = A.B.C.Id <some operator> -1;
当你创建一个新的A实例时,看看哪个会在B中创建C,哪个会在A中创建B。或者把代码放在类的构造函数中创建这样的实例。(所以在A()中创建B,在B()中创建C)


它感觉错误的原因是,正如其他人所指出的,你不应该处于这种情况下

通过A或B或两者来引用C,这是不好的做法。如果需要以这种方式引用某个对象,请使用空构造函数以这种方式构建连接。

在C#中,没有特殊的语法可以执行您想要执行的操作

但是有一些建筑方法,如何做到这一点

你可以使用 或者您可以使用允许null的扩展方法扩展A、B、C类:

var myId = A.BOrNull().COrNull().IdOrNull();

public class A {
    public B B { get; set; }
}
public static class AExtensionMethods {
    public static B BOrNull( this A a ) {
        return null != a ? a.B : null;
    }
}

public class B {
    public C C { get; set; }
}
public static class BExtensionMethods {
    public static C COrNull( this B b ) {
        return null != b ? b.C : null;
    }
}

public class C {
    public int Id { get; set; }
}
public static class CExtensionMethods {
    public static int? IdOrNull( this C c ) {
        return null != c ? (int?)c.Id : null;
    }
}

如果您必须深入研究,您可能希望在中创建一个属性,该属性将为您提供null或B.C.Id。

您可以尝试以下代码:

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

这非常适合设计模式

基本上,像这样定义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的真实实例时,您只需使用并返回它们。

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

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;

-1这是非常糟糕的方式,如何做到这一点。如果经常抛出异常,会使程序运行缓慢,调试也会困难得多。使用异常控制程序流是一种不好的做法。在这种情况下,您可以轻松地首先检查null以避免引发异常。不要将异常用作控制流。如果您详细说明空值检查,您的代码将更具可读性和可维护性。-1使用异常控制程序流是非常糟糕的做法。您可以更好地检查null,或者在类不存在的情况下创建该类的实例。您不应该使用catch块来管理您已经期望的异常。将其设置为-1意味着您知道将发生什么。在这种情况下,检查null异常,并在该条件下将myId设置为-1。它不会解决ID为null的问题,但会解决依赖类(在本例中为B和C)为null的问题,因为它们将使用A创建。即,A依赖于B,因此当A为。B依赖于C,所以这是在B为时创建的。我理解这个问题为“B或C可以为null,并且它是有效状态”。这就是我问题的原因。@TcKs你是对的,我问这个问题是因为null的子对象状态是有效的。空表示“不存在”,它不应该存在,因此DI对我不起作用。因此,我自己的困惑:)取决于你对得墨忒尔定律的严格解释。
person.Name.FirstName
person.Name.LastName
是否违法?我想大多数人不会那么严格。我想他指的是逻辑类。我想任何包含方法的东西。我不知道有一个书面规则+1@鲁本得墨忒尔定律有时会被打破,但是如果你破坏了它,我建议你看看你的结构,看看你是否可以构造你的对象,这样你就不会,因为你越不违反德米特定律,你的代码就越有可能是可测试的,因为你可以在其中注入更多的依赖项。这不是关于违反定律。点数并不是衡量你是否违反了德米特定律的严格标准。有时,“对象”由几个逻辑部分组成,您可以将这些逻辑部分分组为子属性,只是为了更好地提供对象的逻辑设计。即使您的dotcount大于1,您本身也没有违反法律。好吧,这取决于你的解释,这很有趣。我以前没有读过这篇文章,但是我知道规则及其存在的原因,但是重构不是一个选项,正如Damien的回答中提到的,null的对象属性在我的情况下是有效的,因为它是null驱动了额外的逻辑。我想说做得更深:A.我得到{return B==null?-1:B.I}B.我得到{return C==null?-1:C.I}但是,如果你有很多财产,这不是一个选择。我接受这一点作为我问题的答案,因为事实上TcKs尽了最大努力来解决我的问题。我意识到,在理想的世界中,我会重构并摆脱这种情况,但不幸的是,我没有在那里工作:)。
 CLassA A = new ClassA();
 int id = A.B.C.ID;