将对象强制转换为派生类中的对象

本文关键字:对象 派生 转换 | 更新日期: 2023-09-27 18:30:37

我有一个工作正常的类Record

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

我还有一个派生自Record的类Order,它实现了额外的方法,仅适用于某种类型的记录:

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

在我的应用程序中,我有一个 Record 类型的对象theRecord,我想将其转换为 Order ,以便我可以对其调用 Start 方法。

我试着投掷它:

Order r = (Order)theRecord;

但这抛出了一个InvalidCastException.

我想我可以为Order创建一个新的构造函数,它需要一个Record,但我已经有了这个对象(它是通过从数据库中获取记录来构建的)。

我怎样才能正确实现这一点?

将对象强制转换为派生类中的对象

如果你得到一个InvalidCastException那么theRecord就不是Order,你不能投射它。 仅当它创建为 OrderOrder 的子类时,才能强制转换它。

我的猜测是,无论从数据库中获取数据,当它可以创建Order(并将其作为Record返回)时,都会创建一个Record。 像这样:

public Record Fetch(int id)
{
   // ... get data from db
   Record rec;
   if(data.Type = "Order")
      rec = new Order();
   else
      rec = new Record();
   return rec;
}

正如我在评论中所说

你可以将狗投射到动物

,但不能将动物投到狗(除非该动物是狗)。更清楚所有的狗都是动物,但不是所有的动物都是狗

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

要让它工作,你必须做这样的事情

Record record = new Order();

然后你可以像这样投射它

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

您必须转换为新对象,而不是强制转换它。若要执行此操作而不一次编写一个属性的映射代码,最简单的方法是序列化Record对象,然后将其反序列化为Order。你可以使用任何你喜欢的序列化技术(XmlSerializerJavaScriptSerializer、JSON.NET 等)。

这假设所有数据都可以在公共属性中使用普通 getter/setter 访问(在您的示例中没有,但您应该这样做)。如果你不想这样做,你可以使用反射来循环遍历Record的字段,从那里获取值,并使用反射来填充Order的字段。

在实际尝试强制转换之前,您可以使用 isas 运算符来确保某些内容属于某种类型,如下所示:

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

is将检查对象是该确切类型还是继承链的一部分。

as将尝试将对象强制转换为类型,如果不能,则返回 null 而不是异常。

注意:as仅适用于引用类型,不适用于值类型;而is将同时适用于引用类型和值类型。因此,例如,您可以is整数,但不能as整数。