Вызов конструктора ребенок с помощью литья (ChildClass)parentObject; отслеживать изменения


Для отслеживания ревизий класса Page у меня есть класс PageRevision, который наследует от Page и добавляет идентификатор ревизии (Guid RevisionID;).

Если это возможно, как я должен привести существующий объект Page к объекту PageRevision и убедиться, что конструктор PageRevision вызывается для создания нового идентификатора ревизии?

Я мог бы иметь конструктор PageRevision(Page page), который генерирует Guid и копирует все атрибуты страницы, но я хочу автоматизировать его, особенно если класс Page имеет много атрибутов (и я позже добавлю один, и забудьте изменить конструктор копирования).

Желаемое использование

Page page = new Page(123, "Page Title", "Page Body"); // where 123 is page ID
PageRevision revision = (PageRevision)page;
// now revision.RevisionID should be a new Guid.

Page, PageRevision классы:

public class Page
{
    public int ID { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
}

public class PageRevision : Page
{
    public Guid RevisionID { get; set; }

    public PageRevision()
    {
        this.RevisionID = Guid.NewGuid();
    }
}

Редактирование на основе обратной связи:

Помимо теперь очевидной проблемы кастинга (Horse)Animal;, Джон Скит рекомендует композитную ревизию:

public class PageRevision : Page
{
    private readonly Page page;
    private readonly Guid id;
    public Guid RevisionID { get { return id; } }
    public Page Page { get { return page; } }

    public PageRevision(Page page)
    {
        this.id = Guid.NewGuid();
        this.page = page;
    }
}
Однако это сильно отличается от моей модели данных, и я хотел бы сохранить их как можно более похожими. В моей базе данных таблица PageRevisions имеет те же столбцы, что и таблица Pages, ожидайте дополнительного RevisionID колонка. Это легко сделать с помощью триггера базы данных.
  • в свете этого комплексного подхода было бы более разумно иметь PageRevisions для хранения всех данных страницы: a RevisionID, Title и Body, в то время как таблица Pages хранит только URL-адрес Slug и RevisionID, который ссылается на таблицу PageRevisions?
4 2

4 ответа:

Почему бы не сделать класс PageRevision составляют не наследуют?

public class PageRevision : Page
{
    private readonly Page page;
    private readonly Guid id;
    public Guid RevisionID { get { return id; } }
    public Page Page { get { return page; } }

    public PageRevision(Page page)
    {
        this.id = Guid.NewGuid();
        this.page = page;
    }
}

Вы не можете.

Лошадь-это животное, но не всякое животное является лошадью.

Итак, лошадь = > животное возможно, но животное => лошадь нет. И вы пытаетесь превратить свое животное в лошадь.

Конструктор PageRevisionВсегда вызывается независимо от того, приводите вы класс к PageRevision или нет. Так что это вообще не сработает.

Скорее всего, имеет смысл рассказать, почему вы хотите это сделать, потому что вы, скорее всего, делаете это по причинам, которые решаются другими способами.

Во время приведения конструктор не вызывается, так как объект уже создан.

Несмотря на то, что приведение завершится неудачей во время выполнения, вызов страницы не может быть приведен к PageRevision (возможен и другой способ)

В вашем случае я бы добавил RevisionId на вашу страницу базового класса. Если вы создаете объект страницы, он может быть создан с помощью Guid.Пустой. Производные классы могут задать RevisionId, используя конструктор страницы базового класса.

public class Page {

    public Page() {
        RevisionId = Guid.Empty;
    }

    protected Page(Guid revisionId) {
        RevisionId = revisionId;
    }

    public Guid RevisionId {
        get;
        private set;
    }
}

public class PageRevision : Page {

    public PageRevision()
        : base(Guid.NewGuid()) {

    }
}