开发者

Calling child constructor by casting (ChildClass)parentObject; to track revisions

开发者 https://www.devze.com 2022-12-27 18:02 出处:网络
To track revisions of a Page class, I have a PageRevision class which inherits from Page and adds a revision ID (Guid Revis开发者_C百科ionID;).

To track revisions of a Page class, I have a PageRevision class which inherits from Page and adds a revision ID (Guid Revis开发者_C百科ionID;).

If possible, how should I cast an existing Page object to a PageRevision and ensure that the PageRevision constructor is called to create a new revision ID?

I could could have a PageRevision(Page page) constructor which generates the Guid and copies all the Page attributes, but I want to automate it, especially if a Page class has many attributes (and I later add one, and forget to modify the copy constructor).

Desired use

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 classes:

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();
    }
}

Edit based on feedback:

Besides the now-obvious (Horse)Animal; casting problem, Jon Skeet recommends a composite revision:

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;
    }
}

However, this is quite different from my data model and I'd like to keep the two as similar as possible. In my database, the PageRevisions table has the same columns as the Pages table, expect for an extra RevisionID column. This is easy to version with a database trigger.

  • In the light of this composite approach, would it make more sense to have a PageRevisions to store all page data: a RevisionID, Title and Body, while a Pages table only stores an URL Slug and a RevisionID that refers to the PageRevisions table?


Why not make your PageRevision class compose instead of inheriting?

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;
    }
}


You cannot.

A horse is an animal, but not every animal is a horse.

So horse => animal is possible, but animal => horse not. And you are trying to cast your animal into a horse.


The PageRevision constructor ALWAYS gets called regardless if you cast the class to PageRevision or not. So this isn't going to work at all.

It likely makes more sense you tell why you want to do that because you are likely doing that for reasons that are solved in other ways.


During a cast, there is no constructor called, because the object is already created.

Although your cast will fail at runtime, cause Page cannot be cast to PageRevision (the other way is possible)

In your case i would add the RevisionId to your base class Page. If you create a Page object it could be created with Guid.Empty. Derived classes could set the RevisionId using an constructor of your base class Page.

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()) {

    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消