Home > database >  cast child class to another with base class
cast child class to another with base class

Time:12-21

I need to have some Length units that can convert them together

Length class as parent Meter, Centimeter, Millimeter as Childs:

public abstract class Length
{
}

public class Meter: Length
{
   public Meter(double val)
   {
       Value = val;
   }

   public double Value { get; set; }

   public static explicit operator Centimeter(Meter m)
   {
        return new Centimeter(m.Value * 100);
   }

   public static explicit operator Millimeter(Meter m)
   {
        return new Millimeter(m.Value * 1000);
   }
}

public class Centimeter: Length
{

   public Centimeter(double val)
   {
       Value = val;
   }

   public double Value { get; set; }

   public static explicit operator Meter(Centimeter cm)
   {
        return new Meter(cm.Value / 100);
   }

   public static explicit operator Millimeter(Centimeter cm)
   {
        return new Millimeter(cm.Value * 10);
   }
}

public class Millimeter: Length
{

   public Millimeter(double val)
   {
       Value = val;
   }

   public double Value { get; set; }

   public static explicit operator Meter(Millimeter mm)
   {
        return new Meter(mm.Value / 1000);
   }

   public static explicit operator Centimeter(Millimeter mm)
   {
        return new Centimeter(mm.Value / 10);
   }
}

I can cast Meter to Millimeter with this code:

Meter m = new Meter(3)
Millimeter mm = (Millimeter)m; //it's ok. result is 3000

But I need to have base class type to hold my variable:

Length l;
if (true)
   l = new Meter(3);
else
   l = new Centimeter(20)
Millimeter m = (Millimeter)l;//runtime Error

I get runtime error : System.InvalidCastException: 'Unable to cast object of type 'Meter' to type 'Millimeter'.'

CodePudding user response:

What you could do is have the value inside the class always in millimeters. Then you only have to use a factor to multiply/divide by when getting or setting the value. Changing the class then would only change the factor. While this is possible I do not recommend this way and would recommend one Length class with the methods GetMeter() etc. using their factor.

CodePudding user response:

This might be in the direction you are hoping to get. Having one class be able to overall handle either conversion of millimeter, centimeter or meter. In this class sample, I am having the class store the value to the lowest granularity of millimeter. Now, that said, you might even want the millimeters level down to an integer vs a double, unless you want to allow for fraction of millimeter, but your choice.

public class MyLength
{
    // always store at the lowest possible scale here
    private double _millsValue;
    private MyLength( double alwaysMillimeters)
    {
        _millsValue = alwaysMillimeters;
    }

    // have constructor return a MyLength based on whatever type wanted with
    // the STATIC method name make sure it builds out to proper millimeter reference
    public static MyLength Millimeter( double val)
    { return new MyLength(val); }

    // 10 millimeters to 1 centimeter, so an incoming 5 centimeters = 50 millimeters
    public static MyLength Centimeter( double val)
    { return new MyLength(val * 10); }

    // similarly, 1000 millimeters to 1 meter, so 2 meters = 2000 millimeters
    public static MyLength Meter (double val)
    { return new MyLength(val * 1000); }

    // Now, expose public getter / setter that are bound to the
    // underlying _millsValue and divide back out by 10 or 1000 respectively
    public double Millimeters
    {
        get { return _millsValue; }
        set { _millsValue = value; }
    }

    public double Centimeters
    {
        get { return _millsValue / 10; }
        set { _millsValue = value * 10; }
    }

    public double Meters
    {
        get { return _millsValue / 1000; }
        set { _millsValue = value * 1000; }
    }
}

And to show how all applied and getting values out regardless of basis created and handling the conversion for you via getters / setters

public class LengthTest
{
    public LengthTest()
    {
        var L = MyLength.Millimeter(1000);
        var mm = L.Millimeters;     // returns 1000
        var cm = L.Centimeters;     // returns 100
        var m = L.Meters;           // returns 1

        var C = MyLength.Centimeter(3);
        mm = C.Millimeters;     // returns 30
        cm = C.Centimeters;     // returns 3
        m = C.Meters;           // returns .03

        var M = MyLength.Meter(2);
        mm = M.Millimeters;     // returns 2000
        cm = M.Centimeters;     // returns 200
        m = M.Meters;           // returns 2


        // can also SET values based on respective named getter/setter
        var someVal = MyLength.Centimeter(0);
        someVal.Centimeters = 250;
        mm = someVal.Millimeters;     // returns 2500
        cm = someVal.Centimeters;     // returns 250
        m = someVal.Meters;           // returns 2.5

        someVal.Meters = .75;
        mm = someVal.Millimeters;     // returns 750
        cm = someVal.Centimeters;     // returns 75
        m = someVal.Meters;           // returns .75

        someVal.Millimeters = 250;
        mm = someVal.Millimeters;     // returns 250
        cm = someVal.Centimeters;     // returns 25
        m = someVal.Meters;           // returns .25


    }
}
  • Related