我已经扩展了这篇文章中给出的单位转换器类:
https://stackoverflow.com/a/7852721/1474894
这就是我现在拥有的:
https://stackoverflow.com/a/7852721/1474894
这就是我现在拥有的:
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,TValueType>>(); private static ConcurrentDictionary<TUnitType,TValueType>> ConversionsFrom = new ConcurrentDictionary<TUnitType,TValueType>>(); 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,TValueType> conversionTo,TValueType> 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); } }
我有这样的具体实现:
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)); } }
我设法将ToUnit方法作为基类的一部分进行通用,但是使用Fromunit方法,我现在每个具体类都有一个(并且它们看起来都非常相似).我希望能够这样做:
Temperature temperature = Temperature.Fromunit(10,TemperatureUnit.Celcius); Pressure pressure = Pressure.Fromunit(50,PressureUnit.Bar);
…无需在每个具体类中实现Fromunit.因为它是一个静态方法,所以我不能通过使用接口来强制执行.我可以在具体类中有一个公共构造函数,并具有以下内容:
public static T Fromunit<T>(TValueType value,TUnitType unit) where T : new() { BaseValue = Convert(value,BaseUnit); return new T(); }
但我想这不是那么好,我将不得不去:
Temperature temperature = Temperature.Fromunit<Temperature>(10,TemperatureUnit.Celcius);
<温度>我觉得有点多余.
是否有可能以更好的方式实现通用的Fromunit?
编辑:
基本上我想要的是,而不是在每个子类中实现Fromunit:
public static Temperature Fromunit(double value,TemperatureUnit unit) { return new Temperature(Convert(value,BaseUnit)); } public static Pressure Fromunit(double value,PressureUnit unit) { return new Pressure(Convert(value,BaseUnit)); } public static Speed Fromunit(double value,SpeedUnit unit) { return new Speed(Convert(value,BaseUnit)); } ...
…将通用Fromunit放在基类中.
解决方法
<温度> “不太好”的解决方案中的类型参数可能看似多余,但实际上并非如此.当你写作
Temperature temperature = Temperature.Fromunit<Temperature>(10,TemperatureUnit.Celcius);
代码实际上已翻译成
Temperature temperature = UnitBase<TemperatureUnit,double>.Fromunit<Temperature>(10,TemperatureUnit.Celcius);
编译器非常好,允许您使用Temperature访问该方法.因为它实际上调用了UnitBase.Fromunit(),所以它不知道你真的想要使用Temperature,这就是为什么你必须提供它作为一个额外的类型参数.