/// <summary>
        ///     Reads the JSON representation of the object.
        /// </summary>
        /// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader" /> to read from.</param>
        /// <param name="objectType">Type of the object.</param>
        /// <param name="existingValue">The existing value of object being read.</param>
        /// <param name="serializer">The calling serializer.</param>
        /// <returns>
        ///     The object value.
        /// </returns>
        /// <exception cref="UnitsNetException">Unable to parse value and unit from JSON.</exception>
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
            JsonSerializer serializer)
        {
            var vu = serializer.Deserialize<ValueUnit>(reader);
            // A null System.Nullable value was deserialized so just return null.
            if (vu == null)
                return null;

            // "MassUnit.Kilogram" => "MassUnit" and "Kilogram"
            string unitEnumTypeName = vu.Unit.Split('.')[0];
            string unitEnumValue = vu.Unit.Split('.')[1];

            // "MassUnit" => "Mass"
            string unitTypeName = unitEnumTypeName.Substring(0, unitEnumTypeName.Length - "Unit".Length);

            // "UnitsNet.Units.MassUnit,UnitsNet"
            string unitEnumTypeAssemblyQualifiedName = "UnitsNet.Units." + unitEnumTypeName + ",UnitsNet";

            // "UnitsNet.Mass,UnitsNet"
            string unitTypeAssemblyQualifiedName = "UnitsNet." + unitTypeName + ",UnitsNet";

            // -- see http://stackoverflow.com/a/6465096/1256096 for details
            Type reflectedUnitEnumType = Type.GetType(unitEnumTypeAssemblyQualifiedName);
            if (reflectedUnitEnumType == null)
            {
                var ex = new UnitsNetException("Unable to find enum type.");
                ex.Data["type"] = unitEnumTypeAssemblyQualifiedName;
                throw ex;
            }

            Type reflectedUnitType = Type.GetType(unitTypeAssemblyQualifiedName);
            if (reflectedUnitType == null)
            {
                var ex = new UnitsNetException("Unable to find unit type.");
                ex.Data["type"] = unitTypeAssemblyQualifiedName;
                throw ex;
            }

            object unit = Enum.Parse(reflectedUnitEnumType, unitEnumValue);

            // Mass.From() method, assume no overloads exist
            MethodInfo fromMethod = (from m in reflectedUnitType.GetMethods()
                                     where m.Name.Equals("From", StringComparison.InvariantCulture) &&
                                     !m.ReturnType.IsGenericType  // we want the non nullable type
                                     select m).Single();

            // Ex: Mass.From(55, MassUnit.Gram)
            // TODO: there is a possible loss of precision if base value requires higher precision than double can represent.
            // Example: Serializing Information.FromExabytes(100) then deserializing to Information 
            // will likely return a very different result. Not sure how we can handle this?
            return fromMethod.Invoke(null, BindingFlags.Static, null, new[] {vu.Value, unit},
                CultureInfo.InvariantCulture);
        }
Exemplo n.º 2
0
        /// <summary>
        ///     Writes the JSON representation of the object.
        /// </summary>
        /// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter" /> to write to.</param>
        /// <param name="value">The value to write.</param>
        /// <param name="serializer">The calling serializer.</param>
        /// <exception cref="UnitsNetException">Can't serialize 'null' value.</exception>
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            Type unitType = value.GetType();

            FieldInfo[] fields =
                unitType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            if (fields.Length == 0)
            {
                var ex = new UnitsNetException("No private fields found in type.");
                ex.Data["type"] = unitType;
                throw ex;
            }
            if (fields.Length > 1)
            {
                var ex = new UnitsNetException("Expected exactly 1 private field, but found multiple.");
                ex.Data["type"] = unitType;
                throw ex;
            }

            // Unit base type can be double, long or decimal,
            // so make sure we serialize the real type to avoid
            // loss of precision
            FieldInfo baseValueField = fields.First();
            object    baseValue      = baseValueField.GetValue(value);

            // Mass => "MassUnit.Kilogram"
            PropertyInfo baseUnitPropInfo = unitType.GetProperty("BaseUnit");

            // Read static BaseUnit property value
            Enum   baseUnitEnumValue = (Enum)baseUnitPropInfo.GetValue(null, null);
            Type   baseUnitType      = baseUnitEnumValue.GetType();
            string baseUnit          = $"{baseUnitType.Name}.{baseUnitEnumValue}";

            serializer.Serialize(writer, new ValueUnit
            {
                // This might throw OverflowException for very large values?
                // TODO Should we serialize long, decimal and long differently?
                Value = Convert.ToDouble(baseValue),
                Unit  = baseUnit
            });
        }
Exemplo n.º 3
0
        /// <summary>
        ///     Reads the JSON representation of the object.
        /// </summary>
        /// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader" /> to read from.</param>
        /// <param name="objectType">Type of the object.</param>
        /// <param name="existingValue">The existing value of object being read.</param>
        /// <param name="serializer">The calling serializer.</param>
        /// <returns>
        ///     The object value.
        /// </returns>
        /// <exception cref="UnitsNetException">Unable to parse value and unit from JSON.</exception>
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
                                        JsonSerializer serializer)
        {
            if (reader.ValueType != null)
            {
                return(reader.Value);
            }

            object obj = TryDeserializeIComparable(reader, serializer);

            // A null System.Nullable value or a comparable type was deserialized so return this
            if (!(obj is ValueUnit vu))
            {
                return(obj);
            }

            // "MassUnit.Kilogram" => "MassUnit" and "Kilogram"
            string unitEnumTypeName = vu.Unit.Split('.')[0];
            string unitEnumValue    = vu.Unit.Split('.')[1];

            // "UnitsNet.Units.MassUnit,UnitsNet"
            string unitEnumTypeAssemblyQualifiedName = "UnitsNet.Units." + unitEnumTypeName + ",UnitsNet";

            // -- see http://stackoverflow.com/a/6465096/1256096 for details
            Type unitEnumType = Type.GetType(unitEnumTypeAssemblyQualifiedName);

            if (unitEnumType == null)
            {
                var ex = new UnitsNetException("Unable to find enum type.");
                ex.Data["type"] = unitEnumTypeAssemblyQualifiedName;
                throw ex;
            }

            double value     = vu.Value;
            Enum   unitValue = (Enum)Enum.Parse(unitEnumType, unitEnumValue); // Ex: MassUnit.Kilogram

            return(Quantity.From(value, unitValue));
        }
        /// <summary>
        /// Convert a <see cref="ValueUnit"/> to an <see cref="IQuantity"/>
        /// </summary>
        /// <param name="valueUnit">The value unit to convert</param>
        /// <exception cref="UnitsNetException">Thrown when an invalid Unit has been provided</exception>
        /// <returns>An IQuantity</returns>
        protected IQuantity ConvertValueUnit(ValueUnit valueUnit)
        {
            if (valueUnit == null || string.IsNullOrWhiteSpace(valueUnit.Unit))
            {
                return(null);
            }

            var unitParts = valueUnit.Unit.Split('.');

            if (unitParts.Length != 2)
            {
                var ex = new UnitsNetException($"\"{valueUnit.Unit}\" is not a valid unit.");
                ex.Data["type"] = valueUnit.Unit;
                throw ex;
            }

            // "MassUnit.Kilogram" => "MassUnit" and "Kilogram"
            var unitEnumTypeName = unitParts[0];
            var unitEnumValue    = unitParts[1];

            // "UnitsNet.Units.MassUnit,UnitsNet"
            var unitEnumTypeAssemblyQualifiedName = "UnitsNet.Units." + unitEnumTypeName + ",UnitsNet";

            // -- see http://stackoverflow.com/a/6465096/1256096 for details
            var unitEnumType = Type.GetType(unitEnumTypeAssemblyQualifiedName);

            if (unitEnumType == null)
            {
                var ex = new UnitsNetException("Unable to find enum type.");
                ex.Data["type"] = unitEnumTypeAssemblyQualifiedName;
                throw ex;
            }

            var value     = valueUnit.Value;
            var unitValue = (Enum)Enum.Parse(unitEnumType, unitEnumValue); // Ex: MassUnit.Kilogram

            return(Quantity.From(value, unitValue));
        }
Exemplo n.º 5
0
        private static IQuantity ParseValueUnit(ValueUnit vu)
        {
            // "MassUnit.Kilogram" => "MassUnit" and "Kilogram"
            string unitEnumTypeName = vu.Unit.Split('.')[0];
            string unitEnumValue    = vu.Unit.Split('.')[1];

            // "UnitsNet.Units.MassUnit,UnitsNet"
            string unitEnumTypeAssemblyQualifiedName = "UnitsNet.Units." + unitEnumTypeName + ",UnitsNet";

            // -- see http://stackoverflow.com/a/6465096/1256096 for details
            Type unitEnumType = Type.GetType(unitEnumTypeAssemblyQualifiedName);

            if (unitEnumType == null)
            {
                var ex = new UnitsNetException("Unable to find enum type.");
                ex.Data["type"] = unitEnumTypeAssemblyQualifiedName;
                throw ex;
            }

            double value     = vu.Value;
            Enum   unitValue = (Enum)Enum.Parse(unitEnumType, unitEnumValue); // Ex: MassUnit.Kilogram

            return(Quantity.From(value, unitValue));
        }
        /// <summary>
        ///     Writes the JSON representation of the object.
        /// </summary>
        /// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter" /> to write to.</param>
        /// <param name="value">The value to write.</param>
        /// <param name="serializer">The calling serializer.</param>
        /// <exception cref="UnitsNetException">Can't serialize 'null' value.</exception>
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            Type unitType = value.GetType();

            FieldInfo[] fields =
                unitType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            if (fields.Length == 0)
            {
                var ex = new UnitsNetException("No private fields found in type.");
                ex.Data["type"] = unitType;
                throw ex;
            }
            if (fields.Length > 1)
            {
                var ex = new UnitsNetException("Expected exactly 1 private field, but found multiple.");
                ex.Data["type"] = unitType;
                throw ex;
            }

            // Unit base type can be double, long or decimal,
            // so make sure we serialize the real type to avoid
            // loss of precision
            FieldInfo baseValueField = fields.First();
            object baseValue = baseValueField.GetValue(value);

            // Mass => "MassUnit.Kilogram"
            PropertyInfo baseUnitPropInfo = unitType.GetProperty("BaseUnit");

            // Read static BaseUnit property value
            Enum baseUnitEnumValue = (Enum) baseUnitPropInfo.GetValue(null, null);
            Type baseUnitType = baseUnitEnumValue.GetType();
            string baseUnit = string.Format("{0}.{1}", baseUnitType.Name, baseUnitEnumValue);

            serializer.Serialize(writer, new ValueUnit
            {
                // This might throw OverflowException for very large values?
                // TODO Should we serialize long, decimal and long differently?
                Value = Convert.ToDouble(baseValue),
                Unit = baseUnit
            });
        }
Exemplo n.º 7
0
        /// <summary>
        ///     Reads the JSON representation of the object.
        /// </summary>
        /// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader" /> to read from.</param>
        /// <param name="objectType">Type of the object.</param>
        /// <param name="existingValue">The existing value of object being read.</param>
        /// <param name="serializer">The calling serializer.</param>
        /// <returns>
        ///     The object value.
        /// </returns>
        /// <exception cref="UnitsNetException">Unable to parse value and unit from JSON.</exception>
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
                                        JsonSerializer serializer)
        {
            if (reader.ValueType != null)
            {
                return(reader.Value);
            }
            object obj = TryDeserializeIComparable(reader, serializer);
            var    vu  = obj as ValueUnit;

            // A null System.Nullable value or a comparable type was deserialized so return this
            if (vu == null)
            {
                return(obj);
            }

            // "MassUnit.Kilogram" => "MassUnit" and "Kilogram"
            string unitEnumTypeName = vu.Unit.Split('.')[0];
            string unitEnumValue    = vu.Unit.Split('.')[1];

            // "MassUnit" => "Mass"
            string unitTypeName = unitEnumTypeName.Substring(0, unitEnumTypeName.Length - "Unit".Length);

            // "UnitsNet.Units.MassUnit,UnitsNet"
            string unitEnumTypeAssemblyQualifiedName = "UnitsNet.Units." + unitEnumTypeName + ",UnitsNet";

            // "UnitsNet.Mass,UnitsNet"
            string unitTypeAssemblyQualifiedName = "UnitsNet." + unitTypeName + ",UnitsNet";

            // -- see http://stackoverflow.com/a/6465096/1256096 for details
            Type reflectedUnitEnumType = Type.GetType(unitEnumTypeAssemblyQualifiedName);

            if (reflectedUnitEnumType == null)
            {
                var ex = new UnitsNetException("Unable to find enum type.");
                ex.Data["type"] = unitEnumTypeAssemblyQualifiedName;
                throw ex;
            }

            Type reflectedUnitType = Type.GetType(unitTypeAssemblyQualifiedName);

            if (reflectedUnitType == null)
            {
                var ex = new UnitsNetException("Unable to find unit type.");
                ex.Data["type"] = unitTypeAssemblyQualifiedName;
                throw ex;
            }

            object unit = Enum.Parse(reflectedUnitEnumType, unitEnumValue);

            // Mass.From() method, assume no overloads exist
            MethodInfo fromMethod = (from m in reflectedUnitType.GetMethods()
                                     where m.Name.Equals("From", StringComparison.InvariantCulture) &&
                                     !m.ReturnType.IsGenericType  // we want the non nullable type
                                     select m).Single();

            // Ex: Mass.From(55, MassUnit.Gram)
            // TODO: there is a possible loss of precision if base value requires higher precision than double can represent.
            // Example: Serializing Information.FromExabytes(100) then deserializing to Information
            // will likely return a very different result. Not sure how we can handle this?
            return(fromMethod.Invoke(null, BindingFlags.Static, null, new[] { vu.Value, unit },
                                     CultureInfo.InvariantCulture));
        }