Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to instantiate derived class from base class generically
    primarykey
    data
    text
    <p>I have extended the unit converter class given in this post: <a href="https://stackoverflow.com/a/7852721/1474894">https://stackoverflow.com/a/7852721/1474894</a> This is what I have now:</p> <pre><code>public abstract class UnitBase&lt;TUnitType, TValueType&gt; where TUnitType : struct, IComparable, IConvertible, IFormattable { protected static TUnitType BaseUnit; protected static TValueType BaseValue; private static ConcurrentDictionary&lt;TUnitType, Func&lt;TValueType, TValueType&gt;&gt; ConversionsTo = new ConcurrentDictionary&lt;TUnitType, Func&lt;TValueType, TValueType&gt;&gt;(); private static ConcurrentDictionary&lt;TUnitType, Func&lt;TValueType, TValueType&gt;&gt; ConversionsFrom = new ConcurrentDictionary&lt;TUnitType, Func&lt;TValueType, TValueType&gt;&gt;(); public static TValueType Convert(TValueType value, TUnitType from, TUnitType to) { // If both From/To are the same, don't do any work. if (from.Equals(to)) return value; // Convert into the base unit, if required. var valueInBaseUnit = from.Equals(BaseUnit) ? value : ConversionsFrom[from](value); // Convert from the base unit into the requested unit, if required var valueInRequiredUnit = to.Equals(BaseUnit) ? valueInBaseUnit : ConversionsTo[to](valueInBaseUnit); return valueInRequiredUnit; } protected static void RegisterConversion(TUnitType convertToUnit, Func&lt;TValueType, TValueType&gt; conversionTo, Func&lt;TValueType, TValueType&gt; conversionFrom) { if (!ConversionsTo.TryAdd(convertToUnit, conversionTo)) throw new ArgumentException("Already exists", "convertToUnit"); if (!ConversionsFrom.TryAdd(convertToUnit, conversionFrom)) throw new ArgumentException("Already exists", "convertToUnit"); } public static string GetUnit(TUnitType unit) { var type = typeof(TUnitType); if (!type.IsEnum) { throw new ArgumentException(); } return Enums.GetEnumDescription(unit as Enum); } public TValueType InUnit(TUnitType unit) { return Convert(BaseValue, BaseUnit, unit); } } </code></pre> <p>I have concrete implementations like this:</p> <pre><code>public enum TemperatureUnit { [System.ComponentModel.Description("°C")] Celcius, [System.ComponentModel.Description("°F")] Fahrenheit } public class Temperature : UnitBase&lt;TemperatureUnit, double&gt; { static Temperature() { BaseUnit = TemperatureUnit.Celcius; RegisterConversion(TemperatureUnit.Fahrenheit, x =&gt; x * 1.8d + 32d, x =&gt; (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)); } } </code></pre> <p>I managed to make the ToUnit method generic as part of the base class, but with the FromUnit method I now have one per concrete class (and they would all look very similar). I want to be able to do this:</p> <pre><code>Temperature temperature = Temperature.FromUnit(10, TemperatureUnit.Celcius); Pressure pressure = Pressure.FromUnit(50, PressureUnit.Bar); </code></pre> <p>...without having to implement FromUnit in each concrete class. Because it is a static method I cannot force the implementation by using an interface. I could have a public constructor in the concrete classes and have something like:</p> <pre><code>public static T FromUnit&lt;T&gt;(TValueType value, TUnitType unit) where T : new() { BaseValue = Convert(value, unit, BaseUnit); return new T(); } </code></pre> <p>But I guess it is not that nice, and I will have to go:</p> <pre><code>Temperature temperature = Temperature.FromUnit&lt;Temperature&gt;(10, TemperatureUnit.Celcius); </code></pre> <p>The <code>&lt;Temperature&gt;</code> is kind of redundant I think.</p> <p>Is it possible to implement a generic FromUnit in a better way?</p> <p><strong>Edit:</strong> Basically I want, instead of implementing FromUnit in each sub class:</p> <pre><code>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)); } ... </code></pre> <p>...to put generic FromUnit in the base class.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload