/// <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); }
/// <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 }); }
/// <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)); }
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 }); }
/// <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)); }