using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace Connected; /// /// A universal T to double binding converter /// /// Note: currently not in use. Should we ever use it, remove /// the [ExcludeFromCodeCoverage] attribute /// [ExcludeFromCodeCoverage] public class NumericConverter : Converter { protected override double ConvertValue(T? value) { if (value is null) { return double.NaN; } /* * Double */ else if (typeof(T) == typeof(double)) { return (double)(object)value; } else if (typeof(T) == typeof(double?)) { return ((double?)(object)value).Value; } /* * String */ else if (typeof(T) == typeof(string)) { return double.Parse((string)(object)value, NumberStyles.Any, Culture); } /* * SByte */ else if (typeof(T) == typeof(sbyte)) { return System.Convert.ToDouble((sbyte)(object)value); } else if (typeof(T) == typeof(sbyte?)) { return System.Convert.ToDouble(((sbyte?)(object)value).Value); } /* * Byte */ else if (typeof(T) == typeof(byte)) { return System.Convert.ToDouble((byte)(object)value); } else if (typeof(T) == typeof(byte?)) { return System.Convert.ToDouble(((byte?)(object)value).Value); } /* * Short */ else if (typeof(T) == typeof(short)) { return System.Convert.ToDouble((short)(object)value); } else if (typeof(T) == typeof(short?)) { return System.Convert.ToDouble(((short?)(object)value).Value); } /* * Ushort */ else if (typeof(T) == typeof(ushort)) { return System.Convert.ToDouble((ushort)(object)value); } else if (typeof(T) == typeof(ushort?)) { return System.Convert.ToDouble(((ushort?)(object)value).Value); } /* * Int */ else if (typeof(T) == typeof(int)) { return System.Convert.ToDouble((int)(object)value); } else if (typeof(T) == typeof(int?)) { return System.Convert.ToDouble(((int?)(object)value).Value); } /* * Uint */ else if (typeof(T) == typeof(uint)) { return System.Convert.ToDouble((uint)(object)value); } else if (typeof(T) == typeof(uint?)) { return System.Convert.ToDouble(((uint?)(object)value).Value); } /* * Long */ else if (typeof(T) == typeof(long)) { return System.Convert.ToDouble((long)(object)value); } else if (typeof(T) == typeof(long?)) { return System.Convert.ToDouble(((long?)(object)value).Value); } /* * Ulong */ else if (typeof(T) == typeof(ulong)) { return System.Convert.ToDouble((ulong)(object)value); } else if (typeof(T) == typeof(ulong?)) { return System.Convert.ToDouble(((ulong?)(object)value).Value); } /* * Float */ else if (typeof(T) == typeof(float)) { return System.Convert.ToDouble((float)(object)value); } else if (typeof(T) == typeof(float?)) { return System.Convert.ToDouble(((float?)(object)value).Value); } /* * Deimal */ else if (typeof(T) == typeof(decimal)) { return System.Convert.ToDouble((decimal)(object)value); } else if (typeof(T) == typeof(decimal?)) { return System.Convert.ToDouble(((decimal?)(object)value).Value); } else { TriggerError("Unable to convert to double from type " + typeof(T).Name); return double.NaN; } } protected override T? ConvertValueBack(double value) { /* * Double */ if (typeof(T) == typeof(double) || typeof(T) == typeof(double?)) { return (T)(object)value; } /* * String */ else if (typeof(T) == typeof(string)) { return (T)(object)value.ToString(Culture); } /* * Sbyte */ else if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?)) { return (T)(object)System.Convert.ToSByte(value); } /* * Byte */ else if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?)) { return (T)(object)System.Convert.ToByte(value); } /* * Short */ else if (typeof(T) == typeof(short) || typeof(T) == typeof(short?)) { return (T)(object)System.Convert.ToInt16(value); } /* * Ushort */ else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?)) { return (T)(object)System.Convert.ToUInt16(value); } /* * Int */ else if (typeof(T) == typeof(int) || typeof(T) == typeof(int?)) { return (T)(object)System.Convert.ToInt32(value); } /* * Uint */ else if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?)) { return (T)(object)System.Convert.ToUInt32(value); } /* * Long */ else if (typeof(T) == typeof(long) || typeof(T) == typeof(long?)) { return (T)(object)System.Convert.ToInt64(value); } /* * Ulong */ else if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?)) { return (T)(object)System.Convert.ToUInt64(value); } /* * Float */ else if (typeof(T) == typeof(float) || typeof(T) == typeof(float?)) { return (T)(object)System.Convert.ToSingle(value); } /* * Decimal */ else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?)) { return (T)(object)System.Convert.ToDecimal(value); } else { TriggerError($"Conversion to type {typeof(T)} not implemented"); return default; } } #region Floating Point comparison private const double MinNormal = 2.2250738585072014E-308d; public static bool AreEqual(double a, double b, double epsilon = MinNormal) { /* * Copyright (c) Michael Borgwardt */ var absA = Math.Abs(a); var absB = Math.Abs(b); var diff = Math.Abs(a - b); /* * Shortcut, handles infinities */ if (a.Equals(b)) { return true; } else if (a == 0 || b == 0 || absA + absB < MinNormal) { /* * a or b is zero or both are extremely close to it * relative error is less meaningful here */ return diff < epsilon * MinNormal; } else { /* * Use relative error */ return diff / (absA + absB) < epsilon; } } #endregion } [ExcludeFromCodeCoverage] internal static class Number { public static T? To(double d) { if (typeof(T) == typeof(sbyte) && d >= sbyte.MinValue && sbyte.MaxValue >= d) return (T)(object)Convert.ToSByte(d); if (typeof(T) == typeof(byte) && d >= byte.MinValue && byte.MaxValue >= d) return (T)(object)Convert.ToByte(d); if (typeof(T) == typeof(short) && d >= short.MinValue && short.MaxValue >= d) return (T)(object)Convert.ToInt16(d); if (typeof(T) == typeof(ushort) && d >= ushort.MinValue && ushort.MaxValue >= d) return (T)(object)Convert.ToUInt16(d); if (typeof(T) == typeof(int) && d >= int.MinValue && int.MaxValue >= d) return (T)(object)Convert.ToInt32(d); if (typeof(T) == typeof(uint) && d >= uint.MinValue && uint.MaxValue >= d) return (T)(object)Convert.ToUInt32(d); if (typeof(T) == typeof(long) && d >= long.MinValue && long.MaxValue >= d) return (T)(object)Convert.ToInt64(d); if (typeof(T) == typeof(ulong) && d >= ulong.MinValue && ulong.MaxValue >= d) return (T)(object)Convert.ToUInt64(d); if (typeof(T) == typeof(float) && d >= float.MinValue && float.MaxValue >= d) return (T)(object)Convert.ToSingle(d); if (typeof(T) == typeof(double) && d >= double.MinValue && double.MaxValue >= d) return (T)(object)Convert.ToDouble(d); if (typeof(T) == typeof(decimal) && (decimal)d >= decimal.MinValue && decimal.MaxValue >= (decimal)d) return (T)(object)Convert.ToDecimal(d); if (typeof(T) == typeof(sbyte?) && d >= sbyte.MinValue && sbyte.MaxValue >= d) return (T)(object)Convert.ToSByte(d); if (typeof(T) == typeof(byte?) && d >= byte.MinValue && byte.MaxValue >= d) return (T)(object)Convert.ToByte(d); if (typeof(T) == typeof(short?) && d >= short.MinValue && short.MaxValue >= d) return (T)(object)Convert.ToInt16(d); if (typeof(T) == typeof(ushort?) && d >= ushort.MinValue && ushort.MaxValue >= d) return (T)(object)Convert.ToUInt16(d); if (typeof(T) == typeof(int?) && d >= int.MinValue && int.MaxValue >= d) return (T)(object)Convert.ToInt32(d); if (typeof(T) == typeof(uint?) && d >= uint.MinValue && uint.MaxValue >= d) return (T)(object)Convert.ToUInt32(d); if (typeof(T) == typeof(long?) && d >= long.MinValue && long.MaxValue >= d) return (T)(object)Convert.ToInt64(d); if (typeof(T) == typeof(ulong?) && d >= ulong.MinValue && ulong.MaxValue >= d) return (T)(object)Convert.ToUInt64(d); if (typeof(T) == typeof(float?) && d >= float.MinValue && float.MaxValue >= d) return (T)(object)Convert.ToSingle(d); if (typeof(T) == typeof(double?) && d >= double.MinValue && double.MaxValue >= d) return (T)(object)Convert.ToDouble(d); if (typeof(T) == typeof(decimal?) && (decimal)d >= decimal.MinValue && decimal.MaxValue >= (decimal)d) return (T)(object)Convert.ToDecimal(d); return default; } public static double From(T v) { if (typeof(T) == typeof(sbyte)) return Convert.ToDouble((sbyte)(object)v); if (typeof(T) == typeof(byte)) return Convert.ToDouble((byte)(object)v); if (typeof(T) == typeof(short)) return Convert.ToDouble((short)(object)v); if (typeof(T) == typeof(ushort)) return Convert.ToDouble((ushort)(object)v); if (typeof(T) == typeof(int)) return Convert.ToDouble((int)(object)v); if (typeof(T) == typeof(uint)) return Convert.ToDouble((uint)(object)v); if (typeof(T) == typeof(long)) return Convert.ToDouble((long)(object)v); if (typeof(T) == typeof(ulong)) return Convert.ToDouble((ulong)(object)v); if (typeof(T) == typeof(float)) return Convert.ToDouble((float)(object)v); if (typeof(T) == typeof(double)) return Convert.ToDouble((double)(object)v); if (typeof(T) == typeof(decimal)) return Convert.ToDouble((decimal)(object)v); if (typeof(T) == typeof(sbyte?)) return Convert.ToDouble((sbyte?)(object)v); if (typeof(T) == typeof(byte?)) return Convert.ToDouble((byte?)(object)v); if (typeof(T) == typeof(short?)) return Convert.ToDouble((short?)(object)v); if (typeof(T) == typeof(ushort?)) return Convert.ToDouble((ushort?)(object)v); if (typeof(T) == typeof(int?)) return Convert.ToDouble((int?)(object)v); if (typeof(T) == typeof(uint?)) return Convert.ToDouble((uint?)(object)v); if (typeof(T) == typeof(long?)) return Convert.ToDouble((long?)(object)v); if (typeof(T) == typeof(ulong?)) return Convert.ToDouble((ulong?)(object)v); if (typeof(T) == typeof(float?)) return Convert.ToDouble((float?)(object)v); if (typeof(T) == typeof(double?)) return Convert.ToDouble((double?)(object)v); if (typeof(T) == typeof(decimal?)) return Convert.ToDouble((decimal?)(object)v); return default; } }