【问题标题】:using derived class methods in base class在基类中使用派生类方法
【发布时间】:2018-10-12 19:24:53
【问题描述】:

在我的工作中,我试图编写一个车库系统管理。 有一个抽象类车辆(它有轮子列表(也是一个类)、一个引擎和更多不重要的参数), car 源自 vihecle,(也包括摩托车) 而汽车靠燃料做功,汽车靠电做功都是汽车派生出来的。(摩托车也一样)。

每辆车都有其他引擎,因此在构造函数中我使用 i_Engine(which inside Engine) = new WorkedOnFuel(WorkedOnFuel.eFuelType.Soler, 0, 115);

每个 WorkedOnFuel/WorkedOnElectricity 类都有自己的方法来为自己的引擎添加能量(燃料需要燃料类型和升数,电力需要浮动时间来添加)。

有没有可能转换和使用这种方法?

注意:我不能使用界面!

我在这里按类添加代码:

public abstract class Vehicle
{


    private string m_ModelName;
    private string m_LicenseNumber;
    private List<Wheel> m_Wheels;
    private Engine m_Engine;

    public Vehicle(string i_ModelName, string i_LicenseNumber)
    {
        m_ModelName = i_ModelName;
        m_LicenseNumber = i_LicenseNumber;
        m_Wheels = new List<Wheel>();
    }

    public Engine i_Engine
    {
        get
        {
            return m_Engine;
        }
        set
        {
            m_Engine = value;
        }
    }

    public List<Wheel> i_Wheels
    {
        get
        {
            return m_Wheels;
        }
        set
        {
            m_Wheels = value;
        }
    }

    public string i_ModelName
    {
        get
        {
            return m_ModelName;
        }
        set
        {
            m_ModelName = value;
        }
    }

    public string i_LicenseNumber
    {
        get
        {
            return m_LicenseNumber;
        }
        set
        {
            m_LicenseNumber = value;
        }
    }
}

}

public abstract class Engine
{
    private float m_Current;
    private float m_Max;
    private float m_PercentageOfEnergyLeft;

    public Engine(float i_Current, float i_Max)
    {
        m_Current = i_Current;
        m_Max = i_Max;
        m_PercentageOfEnergyLeft = 0;
    }

    public float i_Current
    {
        get
        {
            return m_Current;
        }
        set
        {
            m_Current = value;
        }
    }

    public float i_Max
    {
        get
        {
            return m_Max;
        }
        set
        {
            m_Max = value;
        }
    }

    public float i_PercentageOfEnergyLeft
    {
        get
        {
            return m_PercentageOfEnergyLeft;
        }
        set
        {
            m_PercentageOfEnergyLeft = value;
        }
    }



}

}

public class WorkedOnFuel : Engine
{
    public enum eFuelType
    {
        Soler,
        Octan95,
        Octan96,
        Octan98
    }

    private float m_CurrentFuelAmount;
    private float m_MaxFuelAmount;
    private eFuelType m_FuelType;

    public WorkedOnFuel(eFuelType i_Fueltype, float i_CurrentFuelAmount, float i_MaxFuelAmount) : base(i_CurrentFuelAmount,i_MaxFuelAmount)
    {
        m_FuelType = i_Fueltype;
        m_CurrentFuelAmount = i_CurrentFuelAmount;
        m_MaxFuelAmount = i_MaxFuelAmount;
    }

    public eFuelType i_Fueltype
    {
        get
        {
            return m_FuelType;
        }
        set
        {
            m_FuelType = value;
        }
    }

    public float i_CurrentFuelAmount
    {
        get
        {
            return m_CurrentFuelAmount;
        }
        set
        {
            m_CurrentFuelAmount = value ;
        }
    }

    public float i_MaxFuelAmount
    {
        get
        {
            return m_MaxFuelAmount;
        }
        set
        {
            m_MaxFuelAmount = value;
        }
    }
    public virtual void AddEnergyToEngine(eFuelType i_Type, float i_FuelAmountForAdd)
    {
        if (i_Type == i_Fueltype && i_CurrentFuelAmount + i_FuelAmountForAdd <= i_MaxFuelAmount)

        {
            i_CurrentFuelAmount += i_FuelAmountForAdd;
            i_PercentageOfEnergyLeft = i_CurrentFuelAmount / i_MaxFuelAmount;
        }
    }
}

}

public class WorkedOnElectricity : Engine
{
    private float m_BatteryTime;
    private float m_MaxBatteryTime;

    public WorkedOnElectricity(float i_BatteryTime, float i_MaxBatteryTime): base(i_BatteryTime,i_MaxBatteryTime)
    {
        m_BatteryTime = i_BatteryTime;
        m_MaxBatteryTime = i_MaxBatteryTime;

    }

    public float i_BatteryTime
    {
        get
        {
            return m_BatteryTime;
        }
        set
        {
            m_BatteryTime = value;
        }
    }

    public float i_MaxBatteryTime
    {
        get
        {
            return m_MaxBatteryTime;
        }
        set
        {
            m_MaxBatteryTime = value;
        }
    }

    public virtual void AddEnergyToEngine(float i_HoursToAddTobattery)
    {
        if ((m_BatteryTime + i_HoursToAddTobattery) <= m_MaxBatteryTime)
        {
            i_MaxBatteryTime += i_HoursToAddTobattery;
            i_PercentageOfEnergyLeft = i_BatteryTime / i_MaxBatteryTime;
        }
    }


}

}

我需要的结果是,当主程序中出现问题时 车辆 v = new FuelCar(...) v.i_Engine.---- 无法通过发动机的汽车类型获取电力/燃料的方法。(在构造函数中构建。

燃油车类:

public class FuelCar : Car
{
    private float m_CurrentFuelAmountInCar;

    public FuelCar(string i_ModelName, string i_LicenseNumber, int i_NumberOfDoors, eColor i_ColorType, float i_CurrentPressureInWheel, 
        float i_CurrentFuelAmountInCar): base(i_ModelName, i_LicenseNumber,i_NumberOfDoors,i_ColorType,i_CurrentPressureInWheel)
    {
        i_Engine =  new WorkedOnFuel(WorkedOnFuel.eFuelType.Octan98, 0, 45);
        i_Engine.i_Current = i_CurrentFuelAmountInCar; // עידכון כמות הדלק 
        i_Engine.i_PercentageOfEnergyLeft = i_CurrentFuelAmountInCar / i_Engine.i_Max; // חישוב אחוז שנשאר במנוע 
    }

    public float i_CurrentFuelAmountInCar
    {
        get
        {
            return m_CurrentFuelAmountInCar;
        }
        set
        {
            m_CurrentFuelAmountInCar = value;
        }
    }

}

}

非常感谢您的帮助,并对我的英语和具体问题感到抱歉! 本。

【问题讨论】:

  • 为什么不让AddEnergyToEngine 成为virtual 基类的成员?
  • 因为我在燃料和电力的方法中使用了不同数量的参数
  • 我认为在 OOP 好的设计中,轮子不仅仅是一个列表,我觉得它们是松散的对象,做一个类,可能是 VehicleWheelsWheelsSystem ,所以每个 Vehicle有一个WheelsSystem
  • 有一个轮子类,每个vihecle根据vihecle类型有一个列表
  • “为车辆创建类层次结构”是一项常见的初学者任务,但通常教得不好。您正在学习的教训(可能是无意的)是在您知道如何使用类层次结构之前设计它们会导致不良结果。从另一端开始。 您希望您的类的用户如何使用它们? 让您决定要公开哪些功能。

标签: c# class oop inheritance polymorphism


【解决方案1】:

我相信您所要求的是“沮丧”。在我看来,C# 有可以优雅地处理此操作的语句。 “as”运算符可用于很容易地确定对象的类型。另外,Type 类上还有一个叫 IsInstanceOfType 的方法。

“as”运算符的文档: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as

“IsInstanceOfType”方法的文档: https://msdn.microsoft.com/en-us/library/system.type.isinstanceoftype%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

使用“as”运算符来确定派生类的类型,从而使您能够调用派生类的方法,如下所示:

Vehicle vehicle1 = new FuelCar(...);
Vehicle vehicle2 = new ElectricCar(...);
.
.
.
FuelCar fuelCar = vehicle1 as FuelCar;
if (fuelCar != null)
{
    fuelCar.CallAFuelCarMethod();
}

ElectricCar electricCar = vehicle2 as ElectricCar;
if (electricCar != null)
{
    electricCar.CallAnElectricCarMethod();
}
.
.
.

使用 IsInstanceOfType 方法类似:

if (vehicle.GetType().IsInstanceOfType(typeof(FuelCar))
{
    .
    .
    .
}

可能还有其他方法;但是,这两个都是简单的解决方案。

【讨论】:

  • 虽然这个答案是正确的;向下转换(AFAIK 前向转换不是一件事)是一种代码味道;并且应尽可能避免。
  • 还有;你仍然需要转换 IsInstanceOfType;还不如只使用 is 运算符(更高效的 IIRC)
  • 在 C# 7 中,您可以使用 is-expression 代替。比如if(vehicle1 is FuelCar fuelCar) {fuelCar.CallAFuelCarMethod();}。使用这种方法,fuelCar 将只在 then 语句的范围内。
猜你喜欢
  • 2019-07-25
  • 2014-09-05
  • 2020-03-24
  • 1970-01-01
  • 2015-01-17
  • 2014-03-17
  • 1970-01-01
  • 2013-03-23
相关资源
最近更新 更多