Зачем проверять, является ли переменная класса пустой до создания нового объекта в конструкторе?
С предыдущей командой, с которой я работал, всякий раз, когда новый класс Service был создан для обработки бизнес-логики между слоем данных и уровнем представления, было выполнено следующее:
class DocumentService
{
public DocumentRepository DocumentRepository { get; set; }
public DocumentService()
{
if (DocumentRepository == null) DocumentRepository = new DocumentRepository();
}
}
Я никогда не понимал, почему была проверка на null
. Если конструктор вызывается, это означает, что он должен быть нулевым. Поскольку это новый экземпляр, правильно?
Зачем это делать? Мне кажется, что это лишний шаг, но я не хочу ничего пропускать и передавать его как плохую практику.
Ответы
Ответ 1
В этом точном контексте: Да, это избыточно.
Не существует непосредственной причины для этого кода, он может быть переходом от более старого метода или предвосхищения при реализации с несколькими конструкторами. Но я бы не рекомендовал использовать этот "шаблон" или даже сохранить этот код.
Ответ 2
Ответ 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
Кажется маловероятным, что вы хотите, чтобы пользователи вашего сервиса могли изменять хранилище "на лету".
Ответ 3
Насколько я могу судить, вы абсолютно правы. Нет необходимости проверять null
.
Ответ 4
Может быть, оператор == для DocumentRepository перезаписан.
Ответ 5
Есть один сценарий, который я могу придумать, где это почти имеет смысл, но вам нужно будет работать в среде, где С# не является единственным языком (или вы делаете странные шаги после компиляции, такие как возможно, с помощью Postsharp).
В С# или 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
}
}