我在将继承的类型转换为基类时遇到一个基本问题。我知道这通常是不可能的,即您可以将派生类强制转换为其基类,但事实并非如此。这是我正在努力的示例片段:

假设我已经定义了一个抽象类来表示计算机PCI卡:

public abstract class PciDevice
{
   public abstract int GetDeviceId();
   public abstract String GetVendorName();
}


现在,我创建了3种类型的继承类(设备):

public class GraphicsCard : PciDevice
{
   public override int GetDeviceId() { return 1666; }
   public override String GetVendorName() { return "CoolCorp"; }

   int trianglesPerSecond;
   ChipsetTypeEnum chipsetType;
}

public class AudioCard : PciDevice
{
   public override int GetDeviceId() { return 1999; }
   public override String GetVendorName() { return "ShinyCorp"; }

   int numChannels;
   int samplingRate;
}

public class Modem : PciDevice
{
   public override int GetDeviceId() { return 1234; }
   public override String GetVendorName() { return "BoringCorp"; }

   public int baudRate;
   bool faxEnabled;
}


现在,我在计算机内部定义了一个“插槽”:

public class PciCardSlot
{
   private int slotId;
   private int clockFreq;
   private PciDevice cardInSlot;

   public PciDevice getCard() { return cardInSlot; }

   public void setCard(PciDevice card) { cardInSlot = card; }
}


我有一个插槽数组来代表计算机中的所有插槽:

PciCardSlot [] pciSlotsInComputer = new PciCardSlot[6];


然后,给定插槽ID,我定义一个函数来检索PciDevice对象:

public PciDevice getInsertedCard(int slotId)
{
   return pciSlotsInComputer[slotId].getCard();
}


到目前为止,一切都很好。现在,在代码中的某个地方,我实例化了AudioCard,GraphicsCard和Modem对象,并将它们分配给插槽。

AudioCard a = new AudioCard();
Modem b = new Modem();
GraphicsCard c = new GraphicsCard();
PciCardSlot s0 = new PciCardSlot(); s0.setCard(a);
PciCardSlot s1 = new PciCardSlot(); s1.setCard(b);
PciCardSlot s2 = new PciCardSlot(); s2.setCard(c);
pciSlotsInComputer[0] = s0; pciSlotsInComputer[1] = s1; pciSlotsInComputer[2] = s2;


然后,我有一个如下所示的函数,旨在对Modem对象进行操作:

public setBaudRateForModem(int slotId, int rate)
{
   ((Modem)getInsertedCard(slotId)).baudRate = rate; // Can not cast!!!
}
...
// I know that slot 1 contains a modem, so I do:
setBaudRateForModem(1, 9600);


由于我正尝试从PciDevice对象投射到从PciDevice派生的Modem对象,因此上面的转换不起作用。

我一直在阅读有关此内容的文章,几乎在我所看到的所有地方,人们似乎都认为,如果您需要将基类转换为成员类,那么您的设计就会很糟糕。我的班级层次结构设计不好吗?有什么建议么?谢谢阅读。

最佳答案

好吧,我认为对PciDevices进行多态处理没有内在的问题。框架中内置了许多实例,在这些实例中,有必要将对象转换回“上下文已知”类型。

但是,BaudRate是仅调制解调器属性,因此其定义和逻辑应位于该类中。具有该特定用途的功能不应更高级别。

通常,您的get函数应该是拥有对象上属性的get定义。

本质上,您在尝试访问BaudRate之前需要了解调制解调器的位置。

例如,如果您想更新所有Modem的BaudRates并且Modem类被很好地封装,则您应该能够执行以下操作

void UpdateModemBaudRates(int baudRate)
{
    foreach(PciCardSlot slot in pciSlotsInComputer)
    {
        Modem modem = slot.CardInSlot as Modem;
        if(modem != null)
        {
            modem.BaudRate = baudRate
        }
    }
}


如果很难做到这一点,请查找asis关键字。

当然,Linq拥有更现代的方式来执行此操作,这是克里斯的评论启发的一种方式。

void UpdateModemBaudRates(int baudRate)
{
    pciSlotsInComputer.Select(s => s.CardInSlot).OfType<Modem>().AsParallel().ForAll<Modem>(modem => modem.BaudRate=baudRate);
}

关于c# - 继承与转型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5595699/

10-16 20:15