I have expanded the converter class specified in this post: https://stackoverflow.com/a/3186262/2326322: This is what I have now:
public abstract class UnitBase<TUnitType, TValueType> where TUnitType : struct, IComparable, IConvertible, IFormattable { protected static TUnitType BaseUnit; protected static TValueType BaseValue; private static ConcurrentDictionary<TUnitType, Func<TValueType, TValueType>> ConversionsTo = new ConcurrentDictionary<TUnitType, Func<TValueType, TValueType>>(); private static ConcurrentDictionary<TUnitType, Func<TValueType, TValueType>> ConversionsFrom = new ConcurrentDictionary<TUnitType, Func<TValueType, TValueType>>(); public static TValueType Convert(TValueType value, TUnitType from, TUnitType to) {
I have specific implementations like this:
public enum TemperatureUnit { [System.ComponentModel.Description("°C")] Celcius, [System.ComponentModel.Description("°F")] Fahrenheit } public class Temperature : UnitBase<TemperatureUnit, double> { static Temperature() { BaseUnit = TemperatureUnit.Celcius; RegisterConversion(TemperatureUnit.Fahrenheit, x => x * 1.8d + 32d, x => (x - 32d) / 1.8d); } private Temperature(double value) { BaseValue = value; } public static Temperature FromUnit(double value, TemperatureUnit unit) { return new Temperature(Convert(value, unit, BaseUnit)); } }
I managed to make the generic ToUnit method part of the base class, but with the FromUnit method I now have one for the specific class (and they all look very similar). I want to be able to do this:
Temperature temperature = Temperature.FromUnit(10, TemperatureUnit.Celcius); Pressure pressure = Pressure.FromUnit(50, PressureUnit.Bar);
... without having to execute FromUnit in each particular class. Since this is a static method, I cannot force the implementation to use the interface. I could create a public constructor in specific classes and have something like:
public static T FromUnit<T>(TValueType value, TUnitType unit) where T : new() { BaseValue = Convert(value, unit, BaseUnit); return new T(); }
But I think this is not so good, and I have to go:
Temperature temperature = Temperature.FromUnit<Temperature>(10, TemperatureUnit.Celcius);
<Temperature> I find it unnecessary.
Is it possible to implement a more general FromUnit method?
Edit: Basically, I want, instead of executing FromUnit in each subclass:
public static Temperature FromUnit(double value, TemperatureUnit unit) { return new Temperature(Convert(value, unit, BaseUnit)); } public static Pressure FromUnit(double value, PressureUnit unit) { return new Pressure(Convert(value, unit, BaseUnit)); } public static Speed FromUnit(double value, SpeedUnit unit) { return new Speed(Convert(value, unit, BaseUnit)); } ...
... to host the FromUnit common class in the base class.