Подтвердить что ты не робот

Как избежать вызова виртуальной функции в конструкторе?

В большинстве (если не все) мои сущности Framework POCOs имеют виртуальные функции. Мне нужно, чтобы эти функции были виртуальными, чтобы объекты могли быть ленивыми.

Если я инициализирую Accommodations в конструкторе, тогда я буду вызывать виртуальную функцию в конструкторе, что является плохой практикой.

Но как я могу инициализировать Accommodations, если не в конструкторе?

public class Venue
{
    public Venue()
    {
        Accommodations = new HashSet<Accommodation>();
    }

    public virtual ICollection<Accommodation> Accommodations { get; set; }
}
4b9b3361

Ответ 1

public class Venue
{
    private accommodations_ = new HashSet<Accommodation>();

    public Venue()  { }

    public virtual ICollection<Accommodation> Accommodations 
    {
        get { return accommodations_; }
        set { accommodations_ = value; }
    }
}

Ответ 2

Другой вариант - отметить установщик как закрытый. Это устраняет проблему вызова виртуальных членов в конструкторе.

Как только вы это сделаете, вам необходимо предоставить возможность для вызывающих абонентов (кроме EF) устанавливать это свойство по мере необходимости по вашему дизайну. Вы можете использовать перегруженный конструктор для передачи в списке мест или, возможно, инкапсулировать свою коллекцию (проект, управляемый доменом), и использовать методы для добавления/удаления элементов (обратите внимание: с EF это становится "хакерским", так как ему не хватает поддержки полностью инкапсулированных коллекции, в отличие от NHibernate):

public class Venue
{
    public Venue()
    {
        Accommodations = new HashSet<Accommodation>();
    }

    public Venue(ICollection<Accommodation> accommodations)
    {
        Accommodations = new List<Accommodation>(accommodations);
    }

    public virtual ICollection<Accommodation> Accommodations { get; private set; }
}

Ответ 3

При ленивой загрузке вы даже не инициализируете Accommodations до ее первого доступа, поэтому оставьте его null.

Вы можете обертывать следующим образом, чтобы он автоматически инициализировал себя:

private ICollection<Accommodation> _accommodations;

public virtual ICollection<Accommodation> Accommodations { 
    get { 
        if (_accommodations == null)
        {
             // Initialize or load data here.
             _accommodations = new HashSet<Accommodation>();
        }
        return _accomodations;
    } 
    set {
        _accommodations = value;
    } 
}

Обязательно прочтите комментарий ниже относительно этого решения!

Ответ 4

С инициализацией по умолчанию С# 6.0 его можно упростить без использования частных переменных:

public class Venue
{
    public virtual ICollection<Accommodation> Accommodations {get; set; } = new HashSet<Accommodation>();
}