Cast an object into an object from a derived class

2019-03-02 17:30发布

问题:

I have a class Record that works fine:

public class Record 
{
    protected string table;
    protected string idcolumn;
    public Record(string _table, string _idcol, int _id) 
    {
        table = _table;
        idcolumn = _idcol;
        Id = _id;
    }
}

I also have a class Order that is derived from Record, that implements extra methods, only applicable on a certain type of record:

class Order : Record 
{
    public void Start() 
    {
    }
}

In my application, I have an object theRecord of type Record that I want to cast to Order, so that I can call the Start method on it.

I tried to cast it:

Order r = (Order)theRecord;

but that throws an InvalidCastException.

I am thinking that I could create a new constructor for Order that takes a Record, but I already have the object (which is built by fetching a record from the database).

How could I implement this correctly?

回答1:

As I said in comments

You can cast a Dog to Animal but not Animal to Dog(unless that animal is Dog). More clearer All Dogs are Animal but not all Animals are Dogs

Record record = new Record();
Order order = (Order)record;//wont work since record is some record not an Order

To make it work you've to do something like this

Record record = new Order();

Then you can cast it like this

Order order = (Order)record;//works since record is Order


回答2:

If you get an InvalidCastException then theRecord is not an Order and you can't cast it. You could only cast it if it were created as an Order or a subclass of Order.

My guess is that whatever fetches the data from the database creates a Record when it could create an Order (and return it as a Record). Something like:

public Record Fetch(int id)
{
   // ... get data from db

   Record rec;
   if(data.Type = "Order")
      rec = new Order();
   else
      rec = new Record();

   return rec;
}


回答3:

You'll have to convert into a new object, rather than cast it. To do this without writing the mapping code one property at a time, the easiest way would be to serialize the Record object, then deserialize it as an Order. You can use whatever serialization technique you like (XmlSerializer, JavaScriptSerializer, JSON.NET, etc.).

This assumes that all the data is accessible in public properties with plain getters/setters (which you don't in your example, but you should do). If you don't want to do that, you can use reflection to loop through the fields of Record, getting the values from there, and using reflection to populate the fields of Order.



回答4:

You can use the is and as operators to make sure something is of a certain type before actually trying to cast it, like this:

Record objectToHoldCastedObject;
if(theRecord is Order)
{
    objectToHoldCastedObject = theRecord as Order;
}

The is will check to see if the object is that exact type or is part of the inheritance chain.

The as will attempt to cast the object to the type, if it cannot then it will return null instead of an exception.

Note: as will only work on reference types, not value types; while is will work on both reference types and value types. So you can is an integer, but not as an integer, for example.



标签: c# oop