14

在我之前合作过的一个团队中,每当创建一个新的 Service 类来处理数据层和表示层之间的业务逻辑时,都会执行以下操作:

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

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

我一直不太明白为什么支票null在那里。如果正在调用构造函数,这意味着它必须为 null..因为它是一个新实例,对吗?

为什么要这样做?在我看来,这是一个多余的步骤,但我不想错过任何事情并将其作为不好的做法。

4

5 回答 5

17

在这个确切的上下文中:是的,它是多余的。

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

于 2013-05-22T13:21:52.997 回答
12

Henk 的回答当然是正确的;我只是想补充一点,我怀疑这是从哪里来的。我敢打赌,在过去的某个时候,有人写道:

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

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

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

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

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

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

于 2013-05-22T16:24:30.383 回答
5

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

于 2013-05-22T13:23:07.677 回答
5

可能是 DocumentRepository 的 == 运算符被覆盖。

于 2013-05-22T13:29:02.300 回答
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
  } 

}
于 2013-05-23T06:33:38.263 回答