This repository has been archived by the owner on Jul 5, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #128 from NoxOrg/feature/volume-type
Implemented Volume type #115
- Loading branch information
Showing
13 changed files
with
552 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
using System; | ||
using System.Globalization; | ||
|
||
namespace Nox.Types; | ||
|
||
public abstract class Measurement<TValueObject, TUnitType> : ValueObject<QuantityValue, TValueObject> | ||
where TValueObject : Measurement<TValueObject, TUnitType>, new() | ||
where TUnitType : MeasurementUnit | ||
{ | ||
private const int QuantityValueDecimalPrecision = 6; | ||
|
||
public TUnitType Unit { get; private set; } = default!; | ||
|
||
protected Measurement() : base() { Value = 0; } | ||
|
||
/// <summary> | ||
/// Creates a new instance of <see cref="TValueObject"/> object with the specified <see cref="TUnitType"/>. | ||
/// </summary> | ||
/// <param name="value">The value to create the <see cref="TValueObject"/> with</param> | ||
/// <param name="unit">The <see cref="TUnitType"/> to create the <see cref="TValueObject"/> with</param> | ||
/// <returns></returns> | ||
/// <exception cref="TypeValidationException"></exception> | ||
public static TValueObject From(QuantityValue value, TUnitType unit) | ||
{ | ||
var newObject = new TValueObject | ||
{ | ||
Value = Round(value), | ||
Unit = unit, | ||
}; | ||
|
||
var validationResult = newObject.Validate(); | ||
|
||
if (!validationResult.IsValid) | ||
{ | ||
throw new TypeValidationException(validationResult.Errors); | ||
} | ||
|
||
return newObject; | ||
} | ||
|
||
/// <summary> | ||
/// Validates a <see cref="TValueObject"/> object. | ||
/// </summary> | ||
/// <returns>true if the <see cref="TValueObject"/> value is valid.</returns> | ||
internal override ValidationResult Validate() | ||
{ | ||
var result = Value.Validate(); | ||
|
||
if (Value < 0 && !double.IsNaN((double)Value) && !double.IsInfinity((double)Value)) | ||
{ | ||
result.Errors.Add(new ValidationFailure(nameof(Value), $"Could not create a Nox {typeof(TValueObject).Name} type as negative {typeof(TValueObject).Name.ToLower()} value {Value} is not allowed.")); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
public override string ToString() | ||
=> $"{Value.ToString($"0.{new string('#', QuantityValueDecimalPrecision)}", CultureInfo.InvariantCulture)} {Unit}"; | ||
|
||
/// <summary> | ||
/// Returns a string representation of the <see cref="TValueObject"/> object using the specified <see cref="IFormatProvider"/>. | ||
/// </summary> | ||
/// <param name="formatProvider">The format provider for the measurement value.</param> | ||
/// <returns>A string representation of the <see cref="TValueObject"/> object with the value formatted using the specified <see cref="IFormatProvider"/>.</returns> | ||
public string ToString(IFormatProvider formatProvider) | ||
=> $"{Value.ToString(formatProvider)} {Unit}"; | ||
|
||
protected QuantityValue GetMeasurementIn(TUnitType targetUnit) | ||
{ | ||
var factor = ResolveUnitConversionFactor(Unit, targetUnit); | ||
return Round(Value * factor); | ||
} | ||
|
||
private static QuantityValue Round(QuantityValue value) | ||
=> Math.Round((double)value, QuantityValueDecimalPrecision); | ||
|
||
protected abstract MeasurementConversionFactor<TUnitType> ResolveUnitConversionFactor(TUnitType sourceUnit, TUnitType targetUnit); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace Nox.Types; | ||
|
||
public abstract class MeasurementConversionFactor<TUnitType> where TUnitType : MeasurementUnit | ||
{ | ||
protected abstract Dictionary<(TUnitType, TUnitType), double> DefinedConversionFactors { get; } | ||
|
||
public double Value { get; } | ||
|
||
protected MeasurementConversionFactor(TUnitType sourceUnit, TUnitType targetUnit) | ||
{ | ||
Value = ResolveConversionFactor(sourceUnit, targetUnit); | ||
} | ||
|
||
private double ResolveConversionFactor(TUnitType sourceUnit, TUnitType targetUnit) | ||
{ | ||
var conversion = (sourceUnit, targetUnit); | ||
|
||
if (DefinedConversionFactors.ContainsKey(conversion)) | ||
return DefinedConversionFactors[conversion]; | ||
|
||
|
||
if (sourceUnit == targetUnit) | ||
return 1; | ||
|
||
throw new NotImplementedException($"No conversion defined from {sourceUnit?.Name} to {targetUnit?.Name}."); | ||
} | ||
|
||
public static QuantityValue operator *(QuantityValue value, MeasurementConversionFactor<TUnitType> factor) | ||
=> value * factor.Value; | ||
|
||
public static QuantityValue operator *(MeasurementConversionFactor<TUnitType> factor, QuantityValue value) | ||
=> value * factor; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System; | ||
|
||
namespace Nox.Types; | ||
|
||
public abstract class MeasurementUnit : IComparable | ||
{ | ||
public int Id { get; } | ||
public string Name { get; } | ||
public string Symbol { get; } | ||
|
||
protected MeasurementUnit(int id, string name, string symbol) | ||
{ | ||
Id = id; | ||
Name = name; | ||
Symbol = symbol; | ||
} | ||
|
||
public int CompareTo(object obj) | ||
=> Id.CompareTo(((MeasurementUnit)obj).Id); | ||
|
||
public override bool Equals(object obj) | ||
{ | ||
if (obj is not MeasurementUnit otherValue) | ||
{ | ||
return false; | ||
} | ||
|
||
var isEqualType = GetType().Equals(obj.GetType()); | ||
var isEqualId = Id.Equals(otherValue.Id); | ||
|
||
return isEqualType && isEqualId; | ||
} | ||
|
||
public override int GetHashCode() => Id.GetHashCode(); | ||
|
||
public override string ToString() => Symbol; | ||
|
||
public static bool operator ==(MeasurementUnit? a, MeasurementUnit? b) | ||
{ | ||
if (a is null && b is null) | ||
return true; | ||
|
||
if (a is null || b is null) | ||
return false; | ||
|
||
return a.Equals(b); | ||
} | ||
|
||
public static bool operator !=(MeasurementUnit? a, MeasurementUnit? b) | ||
{ | ||
return !(a == b); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,52 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace Nox.Types; | ||
|
||
/// <summary> | ||
/// Represents a Nox <see cref="Volume"/> type and value object. | ||
/// </summary> | ||
public sealed class Volume : Measurement<Volume, VolumeUnit> | ||
{ | ||
/// <summary> | ||
/// Creates a new instance of <see cref="Volume"/> object in cubic feet. | ||
/// </summary> | ||
/// <param name="value">The value to create the <see cref="Volume"/> with</param> | ||
/// <returns></returns> | ||
/// <exception cref="TypeValidationException"></exception> | ||
public static Volume FromCubicFeet(QuantityValue value) | ||
=> From(value, VolumeUnit.CubicFoot); | ||
|
||
/// <summary> | ||
/// Creates a new instance of <see cref="Volume"/> object in cubic meters. | ||
/// </summary> | ||
/// <param name="value">The origin value to create the <see cref="Volume"/> with</param> | ||
/// <returns></returns> | ||
/// <exception cref="TypeValidationException"></exception> | ||
public static Volume FromCubicMeters(QuantityValue value) | ||
=> From(value, VolumeUnit.CubicMeter); | ||
|
||
/// <summary> | ||
/// Represents a Nox <see cref="Volume"/> type and value object. | ||
/// Creates a new instance of <see cref="Volume"/> object in cubic meters. | ||
/// </summary> | ||
/// <remarks>Placeholder, needs to be implemented</remarks> | ||
public sealed class Volume : ValueObject<QuantityValue, Volume> | ||
/// <param name="value">The origin value to create the <see cref="Volume"/> with</param> | ||
/// <returns></returns> | ||
/// <exception cref="TypeValidationException"></exception> | ||
public new static Volume From(QuantityValue value) | ||
=> From(value, VolumeUnit.CubicMeter); | ||
|
||
private QuantityValue? _cubicFeet; | ||
|
||
public QuantityValue ToCubicFeet() => _cubicFeet ??= GetMeasurementIn(VolumeUnit.CubicFoot); | ||
|
||
private QuantityValue? _cubicMeters; | ||
|
||
public QuantityValue ToCubicMeters() => _cubicMeters ??= GetMeasurementIn(VolumeUnit.CubicMeter); | ||
|
||
protected override IEnumerable<KeyValuePair<string, object>> GetEqualityComponents() | ||
{ | ||
yield return new KeyValuePair<string, object>(nameof(Value), ToCubicMeters()); | ||
} | ||
|
||
protected override MeasurementConversionFactor<VolumeUnit> ResolveUnitConversionFactor(VolumeUnit sourceUnit, VolumeUnit targetUnit) | ||
=> new VolumeConversionFactor(sourceUnit, targetUnit); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace Nox.Types; | ||
|
||
public class VolumeConversionFactor : MeasurementConversionFactor<VolumeUnit> | ||
{ | ||
private static readonly Dictionary<(VolumeUnit, VolumeUnit), double> _definedVolumeConversionFactors = new() | ||
{ | ||
{ (VolumeUnit.CubicFoot, VolumeUnit.CubicMeter), 0.0283168466 }, | ||
{ (VolumeUnit.CubicMeter, VolumeUnit.CubicFoot), 35.3146667 }, | ||
}; | ||
|
||
protected override Dictionary<(VolumeUnit, VolumeUnit), double> DefinedConversionFactors => _definedVolumeConversionFactors; | ||
|
||
public VolumeConversionFactor(VolumeUnit sourceUnit, VolumeUnit targetUnit) | ||
: base(sourceUnit, targetUnit) | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
namespace Nox.Types; | ||
|
||
public class VolumeUnit : MeasurementUnit | ||
{ | ||
public static VolumeUnit CubicMeter { get; } = new VolumeUnit(1, "CubicMeter", "m³"); | ||
public static VolumeUnit CubicFoot { get; } = new VolumeUnit(2, "CubicFoot", "ft³"); | ||
|
||
private VolumeUnit(int id, string name, string symbol) : base(id, name, symbol) | ||
{ | ||
} | ||
} | ||
|
||
|
||
public class LengthUnit : MeasurementUnit | ||
{ | ||
public static LengthUnit Meter { get; } = new LengthUnit(1, "Meter", "m"); | ||
public static LengthUnit Foot { get; } = new LengthUnit(2, "Foot", "ft"); | ||
|
||
protected LengthUnit(int id, string name, string symbol) : base(id, name, symbol) | ||
{ | ||
} | ||
} | ||
|
||
public class DistanceUnit : LengthUnit | ||
{ | ||
protected DistanceUnit(int id, string name, string symbol) : base(id, name, symbol) | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.