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

Можно ли вызвать виртуальные свойства из конструктора объекта NHibernate?

взгляните на этот пример кода:

public class Comment
{
    private Comment()
    { }

    public Comment(string text, DateTime creationDate, string authorEmail)
    {
        Text = text;
        CreationDate = creationDate;
        AuthorEmail = authorEmail;
    }

    public virtual string Text { get; private set; }
    public virtual DateTime CreationDate { get; set; }
    public virtual string AuthorEmail { get; private set; }
}

Я знаю, что считать ошибочной практикой вызов виртуальных функций-членов из конструктора, однако в NHibernate мне нужны виртуальные свойства для поддержки ленивой загрузки. В этом случае считается, что это нормально?

4b9b3361

Ответ 1

Я уверен, что все в порядке, но если вы беспокоитесь, вы всегда можете просто назначить свойства после вызова параметра меньше конструктора.

Ответ 2

Чтобы расширить ответ на Paco:

В большинстве случаев это не повредит. Но если класс наследуется, виртуальный позволяет свойства get/set переопределяться, поэтому поведение больше не полностью инкапсулируется и не контролируется, поэтому теоретически оно может ломаться. FxCop предупреждает об этом, потому что это потенциальная проблема.

Точка FxCop должна помочь предупредить вас о потенциальных проблемах. Неправильно использовать свойства в конструкторе, если вы знаете, кто/что когда-либо наследует от класса, но это не является "лучшей практикой".

Итак, ответ заключается в том, что это нормально, если вы контролируете какое-либо наследование класса. В противном случае не используйте его и напрямую задайте значения полей. (Это означает, что вы не можете использовать автоматические свойства get/set С# 3.0 - вам придется самостоятельно создавать поля для полей свойств.)

Боковое примечание. Лично все мои проекты - это веб-сайты, которые мы размещаем для клиентов. Таким образом, предполагая, что эта настройка остается той же для проекта, чем это стоит компромиссов, чтобы дублировать различные проверки нулевого/аргумента. Но в любом другом случае, когда я не уверен, что мы будем поддерживать полный контроль над проектом и использованием класса, я бы не стал использовать этот ярлык.

Ответ 3

В этом примере все в порядке, но это может вызвать проблемы при наследовании класса и переопределении свойств. Как правило, вы можете создавать поля для виртуальных свойств.

Ответ 4

Я знаю, что FxCop жалуется, если вы вызываете виртуальный метод в своем конструкторе, но я не знаю, что FxCop говорит, вы вызываете виртуальное свойство в своем конструкторе...
Я бы подумал, что FxCop тоже будет жаловаться, поскольку свойство переводится в метод в IL.

Вы также можете создать свои свойства как "не виртуальные" и просто указать "lazy = false" в вашем "сопоставлении классов" в NHIbernate. Это не повлияет на поведение коллекций с ленивой нагрузкой.

(Я делаю это все время, так как мне не нравится, что моя инфраструктура (NHibernate) требует, чтобы у меня были свойства virtual.
Я также не знаю, важно ли преимущество производительности динамических прокси-серверов в NHibernate).

Ответ 5

Я думаю, вы не должны называть его в конструкторе. Вы можете предоставить метод Initialize(), который вы можете вызвать после построения объекта.

В Initialize() вы можете вызвать необходимые виртуальные методы

Ответ 6

IMHO лучшей практикой является использование свойств с полями поддержки:

public class Comment
{
    private DateTime _creationDate;
    private string _text;
    private string _authorEmail;
    private Comment() { }
    public Comment(string text, DateTime creationDate, string authorEmail)
    {
        _text = text;
        _creationDate = creationDate;
        _authorEmail = authorEmail;
    }
    public virtual string Text
    {
        get { return _text; }
        private set { _text = value; }
    }
    public virtual string AuthorEmail
    {
        get { return _authorEmail; }
        private set { _authorEmail = value; }
    }
    public virtual DateTime CreationDate
    {
        get { return _creationDate; }
        set { _creationDate = value; }
    }
}

Таким образом, вы можете избежать проблем с дочерними классами и больше не видите никаких предупреждений