/// <summary> /// Converts this quantity from this <see cref="Unit"/> to another <see cref="MeasureUnit"/>. /// Must be called only if <see cref="CanConvertTo(MeasureUnit)"/> returned true otherwise an <see cref="ArgumentException"/> /// is thrown. /// </summary> /// <param name="u">The target unit of measure.</param> /// <returns>The quantity exporessed with the target unit.</returns> public Quantity ConvertTo(MeasureUnit u) { if (Unit == u) { return(this); } if (!CanConvertTo(u)) { if (u.Context != Unit.Context) { throw new ArgumentException($"Can not convert between units in different contexts ('{Unit}' to '{u}')."); } throw new ArgumentException($"Can not convert from '{Unit}' to '{u}'."); } if (Unit.Normalization == u.Normalization) { FullFactor ratio = Unit.NormalizationFactor.DivideBy(u.NormalizationFactor); return(new Quantity(Value * ratio.ToDouble(), u)); } else { FullFactor ratio = Unit.NormalizationFactor.Multiply(u.NormalizationFactor); return(new Quantity(1 / (Value * ratio.ToDouble()), u)); } }
/// <summary> /// Defines an alias. /// The same alias can be registered multiple times but it has to exactly match the previously registered one. /// </summary> /// <param name="abbreviation"> /// The unit of measure abbreviation. /// This is the key that is used. It must not be null or empty. /// </param> /// <param name="name">The full name. Must not be null or empty.</param> /// <param name="definitionFactor"> /// The factor that applies to the <see cref="AliasMeasureUnit.Definition"/>. /// Must not be <see cref="FullFactor.Zero"/>. /// </param> /// <param name="definition">The definition. Can be any <see cref="MeasureUnit"/>.</param> /// <param name="autoStandardPrefix"> /// Whether standard metric and/or binary prefixes can be applied to the unit. /// </param> /// <returns>The alias unit of measure.</returns> public AliasMeasureUnit DefineAlias( string abbreviation, string name, FullFactor definitionFactor, MeasureUnit definition, AutoStandardPrefix autoStandardPrefix = AutoStandardPrefix.None) { if (!IsValidNewAbbreviation(abbreviation, autoStandardPrefix)) { throw new ArgumentException($"Invalid abbreviation {abbreviation}.", nameof(abbreviation)); } if (String.IsNullOrWhiteSpace(name)) { throw new ArgumentException("Must not be null or white space.", nameof(name)); } if (definitionFactor.IsZero) { throw new ArgumentException("Must not be zero.", nameof(definitionFactor)); } if (definition == null) { throw new ArgumentNullException(nameof(definition)); } if (definition != MeasureUnit.None && definition.Context != this) { throw new Exception("Units' Context mismatch."); } return(RegisterAlias(abbreviation, name, definitionFactor, definition, autoStandardPrefix)); }
AliasMeasureUnit RegisterAlias(string a, string n, FullFactor f, MeasureUnit d, AutoStandardPrefix stdPrefix) { if (d == MeasureUnit.None) { if (f.Factor != 1.0) { throw new ArgumentException("Only exponential factor is allowed for dimensionless units."); } d = RegisterPrefixed(f.ExpFactor, MeasureStandardPrefix.None, MeasureUnit.None, false); f = FullFactor.Neutral; } return(Register(abbreviation: a, name: n, creator: () => new AliasMeasureUnit(this, a, n, f, d, stdPrefix), checker: m => { if (m.Definition.Normalization != d.Normalization) { ThrowArgumentException(m, $"new definition unit '{d}' is not compatible with '{m.Definition}'."); } if (m.NormalizationFactor != d.NormalizationFactor.Multiply(f)) { ThrowArgumentException(m, $"new normalization factor '{f}' should be '{m.NormalizationFactor.DivideBy(d.NormalizationFactor)}'."); } CheckArgumentAutoStdPrefix(m, stdPrefix); })); }
internal AliasMeasureUnit( MeasureContext ctx, string abbreviation, string name, FullFactor definitionFactor, MeasureUnit definition, AutoStandardPrefix stdPrefix) : base(ctx, abbreviation, name, stdPrefix, false) { DefinitionFactor = definitionFactor; Definition = definition; }
/// <summary> /// This ctor is used by <see cref="AtomicMeasureUnit"/>: it initializes a /// MeasureUnit bound to itself. /// </summary> /// <param name="ctx">The context.</param> /// <param name="abbreviation">The abbreviation.</param> /// <param name="name">The name.</param> /// <param name="isNormalized">True if this measure unit is the normalized one for its dimension.</param> private protected MeasureUnit(MeasureContext ctx, string abbreviation, string name, bool isNormalized) { _ctx = ctx; Abbreviation = abbreviation; Name = name; _units = new[] { (ExponentMeasureUnit)this }; if (isNormalized) { _normalizationFactor = FullFactor.Neutral; _normalization = this; if (ctx == null) { _invert = this; } } }
/// <summary> /// Compares this quantity to another one. /// </summary> /// <param name="other">The other quantity to compare.</param> /// <returns></returns> public int CompareTo(Quantity other) { var tU = Unit; var oU = other.Unit; // Do the 2 units belong to the same (possibly null) context? if (tU.Context == oU.Context) { // First chexk our equality: we must do this first to ensure coherency. if (ToNormalizedString() == other.ToNormalizedString()) { return(0); } // Same unit, we compare the Values. if (tU == oU) { return(Value.CompareTo(other.Value)); } // Same normalized units, we convert this Value to the other unit before comparison. if (tU.Normalization == oU.Normalization) { FullFactor ratio = tU.NormalizationFactor.DivideBy(oU.NormalizationFactor); return((Value * ratio.ToDouble()).CompareTo(other.Value)); } // Inverted normalized units, we convert this Value to the other unit before comparison. if (tU.Normalization == oU.Normalization.Invert()) { FullFactor ratio = tU.NormalizationFactor.Multiply(oU.NormalizationFactor); return((1 / (Value * ratio.ToDouble())).CompareTo(other.Value)); } // No possible conversion. How to compare kilograms and milliSievert? // Using their abbreviation (here kilogram will be "smaller" than milliSievert) return(tU.Abbreviation.CompareTo(oU.Abbreviation)); } // Not in the same context. if (tU == MeasureUnit.None) { return(-1); } if (oU == MeasureUnit.None) { return(1); } return(tU.Context.Name.CompareTo(oU.Context.Name)); }
AliasMeasureUnit RegisterAlias(string a, string n, FullFactor f, MeasureUnit d, AutoStandardPrefix stdPrefix) { if (d == MeasureUnit.None) { if (f.Factor != 1.0) { throw new Exception("Only exponential factor is allowed for dimensionless units."); } d = RegisterPrefixed(f.ExpFactor, MeasureStandardPrefix.None, MeasureUnit.None, false); f = FullFactor.Neutral; } return(Register(abbreviation: a, name: n, creator: () => new AliasMeasureUnit(this, a, n, f, d, stdPrefix), checker: m => m.Definition.Normalization == d.Normalization && m.NormalizationFactor == d.NormalizationFactor.Multiply(f) && m.AutoStandardPrefix == stdPrefix)); }