为什么在构造函数中实例化新对象之前检查类变量是否为null?

时间:2013-05-22 13:20:46

标签: c# .net constructor

在我使用的前一个团队中,每当创建一个新的Service类来处理数据层和表示层之间的业务逻辑时,就会完成以下操作:

class DocumentService
{
    public DocumentRepository DocumentRepository { get; set; }

    public DocumentService()
    {
         if (DocumentRepository == null) DocumentRepository = new DocumentRepository();
    }
}

我从未完全理解为什么null的检查存在。如果正在调用构造函数,那意味着它必须为null ..因为它是一个新实例,对吧?

为什么要这样做?在我看来,这似乎是一个多余的步骤,但我不想错过任何东西并将其作为不好的做法传递下去。

5 个答案:

答案 0 :(得分:17)

在这个确切的背景下:是的,这是多余的。

此代码没有直接的原因,它可能是旧方法的遗留问题或预期具有多个构造函数的实现。但我不建议使用这个'模式',甚至不保留这些代码。

答案 1 :(得分:12)

亨克的回答当然是正确的;我只是想补充一点,我怀疑它来自何处。我敢打赌,在过去的某个时候有人写道:

class DocumentService
{
    private DocumentRespository documentRespository = null;
    public DocumentRepository DocumentRepository 
    { 
        get
        {
            if (documentRepository == null) 
                documentRepository = new DocumentRepository();
            return documentRepository;
        }
    }
    public DocumentService()
    {
    }
}

也就是说,该属性在首次使用时初始化 。后来有人意识到这是错误的或不必要的,或者其他什么,并重写代码将构造放在构造函数中,使属性“渴望”而不是“懒惰”,但忘记取出空检查。

如果人们通过从现有代码剪切和粘贴到新代码进行编程,则该模式可以传播。很快,一个神话就出现了,这就是它必须要做的事情。这就是为什么,我怀疑,如此多的Visual Basic程序员都错误地认为,当你完成Foo时,你必须说Set Foo = Nothing;在某些情况下,这是必要的,现在人们即使在没有必要的情况下也会这样做,因为这就是我们在这里做的事情。

顺便说一句,你可能想说:

public DocumentRepository DocumentRepository { get; private set; } // note the private

您似乎不太可能希望您的服务用户能够动态更改存储库。

答案 2 :(得分:5)

据我所知,你是绝对正确的。无需检查null

答案 3 :(得分:5)

可能会覆盖DocumentRepository的==运算符。

答案 4 :(得分:1)

有一个场景,我可以想到这几乎有意义 - 但你必须在一个C#不是唯一语言的环境中工作(或者你正在进行奇怪的后编译步骤,比如Postsharp可能是可能的。

在C#或VB.Net中,您无法控制何时调用基类构造函数,并且没有语法允许您在调用基类构造函数之前设置基类成员 - 但是没有什么可以阻止它在IL。

如果您在这样的环境中工作,并且您显示的构造函数实际上对DocumentRepository做了更多的事情,那么您可能正在为以下类正确设置:

public class IllegalCSharpClass : DocumentService
{
    public IllegalCSharpClass()
    {
        DocumentRepository = new DocumentRepository("B");
        base(); //This is illegal C#, but allowed in IL
    }
}

我不想在这样的工作场所工作。

以下是该课程的IL:

.class public auto ansi beforefieldinit PlayAreaCS_Con.IllegalCSharpClass
       extends PlayAreaCS_Con.DocumentService
{
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    .maxstack  8
    IL_0008:  ldarg.0
    IL_0009:  ldstr      "B"
    IL_000e:  newobj     instance void PlayAreaCS_Con.DocumentRepository::.ctor(string)
    IL_0013:  call       instance void PlayAreaCS_Con.DocumentService::set_DocumentRepository(class PlayAreaCS_Con.DocumentRepository)
    IL_0018:  nop
    IL_0019:  nop
    IL_0000:  ldarg.0
    IL_0001:  call       instance void PlayAreaCS_Con.DocumentService::.ctor()
    IL_0006:  nop
    IL_0007:  nop
    IL_001a:  ret
  } 

}