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
}
}