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: aRevisionID
,Title
andBody
, while aPages
table only stores an URLSlug
and aRevisionID
that refers to thePageRevisions
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()) {
}
}
精彩评论