Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
if (!(value is IQuantity quantity))
throw new ArgumentException("Expected value of type UnitsNet.IQuantity.", nameof(value));

Enum unitEnumValue = _settings.GetDefaultUnit(quantity.QuantityInfo.UnitType);
Enum unitEnumValue = _settings.GetDefaultUnit(quantity.GetQuantityInfo().UnitType);
int significantDigits = _settings.SignificantDigits;

IQuantity quantityInUnit = quantity.ToUnit(unitEnumValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public double ConvertOnce()
double result = 0;
foreach (IQuantity quantity in Quantities)
{
foreach (UnitInfo unitInfo in quantity.QuantityInfo.UnitInfos)
foreach (UnitInfo unitInfo in quantity.GetQuantityInfo().UnitInfos)
{
result = quantity.As(unitInfo.Value);
}
Expand Down
2 changes: 2 additions & 0 deletions UnitsNet.Serialization.JsonNet/AbbreviatedUnitsConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ public override void WriteJson(JsonWriter writer, IQuantity? quantity, JsonSeria
/// <returns>The string representation associated with the given quantity</returns>
protected string GetQuantityType(IQuantity quantity)
{
#pragma warning disable CS0618 // IQuantity.QuantityInfo: serialization must work for custom quantities not registered in UnitsNetSetup.Default.
return _quantities[quantity.QuantityInfo.Name].Name;
#pragma warning restore CS0618
}

/// <inheritdoc />
Expand Down
2 changes: 2 additions & 0 deletions UnitsNet.Serialization.JsonNet/UnitsNetBaseJsonConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ protected ValueUnit ConvertIQuantity(IQuantity quantity)
{
quantity = quantity ?? throw new ArgumentNullException(nameof(quantity));

#pragma warning disable CS0618 // IQuantity.QuantityInfo: serialization must work for custom quantities not registered in UnitsNetSetup.Default.
return new ValueUnit {Value = (double)quantity.Value, Unit = $"{quantity.QuantityInfo.UnitType.Name}.{quantity.Unit}"};
#pragma warning restore CS0618
}

/// <summary>
Expand Down
52 changes: 52 additions & 0 deletions UnitsNet.Tests/CustomCode/IQuantityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,58 @@ public void GetUnitInfo_MatchesUnit()
});
}

[Fact]
public void GetQuantityInfo_NonGeneric_ReturnsRegisteredQuantityInfo()
{
IQuantity quantity = new Mass(1.0, MassUnit.Kilogram);

QuantityInfo info = quantity.GetQuantityInfo();

Assert.Same(Mass.Info, info);
}

[Fact]
public void GetQuantityInfo_Typed_ReturnsRegisteredQuantityInfo()
{
IQuantity<MassUnit> quantity = new Mass(1.0, MassUnit.Kilogram);

QuantityInfo<MassUnit> info = quantity.GetQuantityInfo();

Assert.Same(Mass.Info, info);
}

[Fact]
public void StaticAbstract_Info_ReturnsSameAsTypedInfo()
{
// Calls IQuantity<TSelf, TUnitType>.Info via the static abstract member.
QuantityInfo<Mass, MassUnit> typedInfo = Mass.Info;
QuantityInfo<Mass, MassUnit> viaStaticAbstract = StaticAbstractAccess<Mass, MassUnit>();

Assert.Same(typedInfo, viaStaticAbstract);

static QuantityInfo<TSelf, TUnit> StaticAbstractAccess<TSelf, TUnit>()
where TSelf : IQuantity<TSelf, TUnit>
where TUnit : struct, Enum
{
return TSelf.Info;
}
}

[Fact]
public void StaticAbstract_Info_NonGeneric_ReturnsSameAsTypedInfo()
{
// Calls IQuantityOfType<TQuantity>.Info via the static abstract member.
QuantityInfo info = StaticAbstractAccess<Mass>();

Assert.Same((QuantityInfo)Mass.Info, info);

static QuantityInfo StaticAbstractAccess<TQuantity>()
where TQuantity : IQuantityOfType<TQuantity>
{
return TQuantity.Info;
}
}

[Fact]
public void ToUnit_UnitSystem_ThrowsArgumentExceptionIfNotSupported()
{
Expand Down
2 changes: 1 addition & 1 deletion UnitsNet.Tests/CustomQuantities/HowMuch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public double As(HowMuchUnit unit)

#region IQuantity

public static readonly QuantityInfo<HowMuch, HowMuchUnit> Info = new(
public static QuantityInfo<HowMuch, HowMuchUnit> Info { get; } = new(
nameof(HowMuch),
HowMuchUnit.Some,
new UnitDefinition<HowMuchUnit>[]
Expand Down
4 changes: 4 additions & 0 deletions UnitsNet/Extensions/LinearQuantityExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,11 @@ public static TQuantity Sum<TQuantity, TUnit>(this IEnumerable<TQuantity> quanti
resultValue += enumerator.Current!.GetValue(unitKey);
}

#if NET
return TQuantity.From(resultValue, unit);
#else
return firstQuantity.QuantityInfo.From(resultValue, unit);
#endif
}

/// <summary>
Expand Down
12 changes: 12 additions & 0 deletions UnitsNet/Extensions/LogarithmicQuantityExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,11 @@ public static TQuantity Sum<TQuantity, TUnit>(this IEnumerable<TQuantity> quanti
sumInLinearSpace += enumerator.Current!.GetValue(unitKey).ToLinearSpace(logarithmicScalingFactor);
}

#if NET
return TQuantity.From(sumInLinearSpace.ToLogSpace(logarithmicScalingFactor), targetUnit);
#else
return firstQuantity.QuantityInfo.From(sumInLinearSpace.ToLogSpace(logarithmicScalingFactor), targetUnit);
#endif
}

/// <summary>
Expand Down Expand Up @@ -342,7 +346,11 @@ public static TQuantity ArithmeticMean<TQuantity, TUnit>(this IEnumerable<TQuant
}

var avgInLinearSpace = sumInLinearSpace / nbQuantities;
#if NET
return TQuantity.From(avgInLinearSpace.ToLogSpace(logarithmicScalingFactor), unit);
#else
return firstQuantity.QuantityInfo.From(avgInLinearSpace.ToLogSpace(logarithmicScalingFactor), unit);
#endif
}

/// <summary>
Expand Down Expand Up @@ -473,7 +481,11 @@ public static TQuantity GeometricMean<TQuantity, TUnit>(this IEnumerable<TQuanti
}

var geometricMean = RootN(sumInLogSpace, nbQuantities);
#if NET
return TQuantity.From(geometricMean, unitKey.ToUnit<TUnit>());
#else
return firstQuantity.QuantityInfo.From(geometricMean, unitKey.ToUnit<TUnit>());
#endif
}

/// <summary>
Expand Down
40 changes: 38 additions & 2 deletions UnitsNet/Extensions/QuantityExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,30 @@ namespace UnitsNet;
/// </summary>
public static class QuantityExtensions
{
/// <summary>
/// Gets the <see cref="UnitsNet.QuantityInfo"/> for the given quantity instance, looked up via
/// <see cref="UnitsNetSetup.Default"/>.
/// </summary>
/// <remarks>
/// Use the static <c>TSelf.Info</c> directly when you have a typed quantity reference for the best performance.
/// This extension is convenient when working with an <see cref="IQuantity"/> reference where the concrete
/// type is not known at compile time.
/// </remarks>
/// <param name="quantity">The quantity instance.</param>
/// <returns>The <see cref="UnitsNet.QuantityInfo"/> registered in <see cref="UnitsNetSetup.Default"/> for the quantity's runtime type.</returns>
public static QuantityInfo GetQuantityInfo(this IQuantity quantity)
{
return UnitsNetSetup.Default.Quantities.GetQuantityInfo(quantity.GetType());
}

/// <inheritdoc cref="GetQuantityInfo(IQuantity)"/>
/// <typeparam name="TUnit">The unit enum type of the quantity.</typeparam>
public static QuantityInfo<TUnit> GetQuantityInfo<TUnit>(this IQuantity<TUnit> quantity)
where TUnit : struct, Enum
{
return (QuantityInfo<TUnit>)UnitsNetSetup.Default.Quantities.GetQuantityInfo(quantity.GetType());
}

/// <summary>
/// Gets the <see cref="UnitInfo"/> for the unit this quantity was constructed with.
/// </summary>
Expand All @@ -24,7 +48,7 @@ public static class QuantityExtensions
/// <returns>The <see cref="UnitInfo"/> for the quantity's unit.</returns>
public static UnitInfo GetUnitInfo(this IQuantity quantity)
{
return quantity.QuantityInfo[quantity.UnitKey];
return quantity.GetQuantityInfo()[quantity.UnitKey];
}

/// <summary>
Expand All @@ -44,7 +68,11 @@ public static UnitInfo<TQuantity, TUnit> GetUnitInfo<TQuantity, TUnit>(this IQua
where TQuantity : IQuantity<TQuantity, TUnit>
where TUnit : struct, Enum
{
#if NET
return TQuantity.Info[quantity.Unit];
#else
return quantity.QuantityInfo[quantity.Unit];
#endif
}

/// <inheritdoc cref="IQuantity.As(UnitKey)" />
Expand Down Expand Up @@ -72,7 +100,11 @@ internal static double GetValue<TQuantity>(this TQuantity quantity, UnitKey toUn
public static double As<TQuantity>(this TQuantity quantity, UnitSystem unitSystem)
where TQuantity : IQuantity
{
#if NET
return quantity.GetValue(quantity.GetQuantityInfo().GetDefaultUnit(unitSystem).UnitKey);
#else
return quantity.GetValue(quantity.QuantityInfo.GetDefaultUnit(unitSystem).UnitKey);
#endif
}

/// <summary>
Expand Down Expand Up @@ -100,7 +132,7 @@ public static TQuantity ToUnit<TQuantity>(this TQuantity quantity, UnitSystem un
where TQuantity : IQuantityOfType<TQuantity>
{
#if NET
QuantityInfo quantityInfo = quantity.QuantityInfo;
QuantityInfo quantityInfo = TQuantity.Info;
UnitKey unitKey = quantityInfo.GetDefaultUnit(unitSystem).UnitKey;
return TQuantity.Create(quantity.As(unitKey), unitKey);
#else
Expand Down Expand Up @@ -277,6 +309,10 @@ internal static TQuantity ArithmeticMean<TQuantity, TUnit>(this IEnumerable<TQua
nbValues++;
}

#if NET
return TQuantity.From(sumOfValues / nbValues, unit);
#else
return firstQuantity.QuantityInfo.From(sumOfValues / nbValues, unit);
#endif
}
}
34 changes: 33 additions & 1 deletion UnitsNet/IQuantity.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed under MIT No Attribution, see LICENSE file at the root.
// Licensed under MIT No Attribution, see LICENSE file at the root.
// Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet.

namespace UnitsNet
Expand All @@ -11,6 +11,13 @@ public interface IQuantity : IFormattable
/// <summary>
/// Information about the quantity type, such as unit values and names.
/// </summary>
/// <remarks>
/// Kept for back-compat with netstandard2.0. On .NET 5+, prefer the static <c>TSelf.Info</c>
/// property or the <c>GetQuantityInfo()</c> extension method on <see cref="QuantityExtensions"/>.
/// </remarks>
#if NET
[Obsolete("Kept for back-compat with netstandard2.0. On .NET 5+, use the static TSelf.Info property or the GetQuantityInfo() extension method.")]
#endif
QuantityInfo QuantityInfo { get; }

/// <summary>
Expand Down Expand Up @@ -82,6 +89,9 @@ public interface IQuantity<TUnitType> : IQuantity
new TUnitType Unit { get; }

/// <inheritdoc cref="IQuantity.QuantityInfo"/>
#if NET
[Obsolete("Kept for back-compat with netstandard2.0. On .NET 5+, use the static TSelf.Info property or the GetQuantityInfo() extension method.")]
#endif
new QuantityInfo<TUnitType> QuantityInfo { get; }

/// <summary>
Expand All @@ -96,10 +106,12 @@ public interface IQuantity<TUnitType> : IQuantity

#region Implementation of IQuantity

#pragma warning disable CS0618 // Type or member is obsolete
QuantityInfo IQuantity.QuantityInfo
{
get => QuantityInfo;
}
#pragma warning restore CS0618

Enum IQuantity.Unit
{
Expand All @@ -121,6 +133,16 @@ public interface IQuantityOfType<out TQuantity> : IQuantity
where TQuantity : IQuantity
{
#if NET
/// <summary>
/// The static <see cref="UnitsNet.QuantityInfo"/> for this quantity type.
/// </summary>
/// <remarks>
/// Implemented by every quantity as a public static <c>Info</c> property. Prefer this and the
/// <see cref="QuantityExtensions.GetQuantityInfo(IQuantity)"/> extension method over the
/// obsolete instance <see cref="IQuantity.QuantityInfo"/> property.
/// </remarks>
public static abstract QuantityInfo Info { get; }

/// <summary>
/// Creates an instance of the quantity from a specified value and unit.
/// </summary>
Expand All @@ -144,9 +166,15 @@ public interface IQuantity<TSelf, TUnitType> : IQuantityOfType<TSelf>, IQuantity
where TUnitType : struct, Enum
{
/// <inheritdoc cref="IQuantity.QuantityInfo"/>
#if NET
[Obsolete("Kept for back-compat with netstandard2.0. On .NET 5+, use the static TSelf.Info property or the GetQuantityInfo() extension method.")]
#endif
new QuantityInfo<TSelf, TUnitType> QuantityInfo { get; }

#if NET
/// <inheritdoc cref="IQuantityOfType{TQuantity}.Info"/>
public new static abstract QuantityInfo<TSelf, TUnitType> Info { get; }

/// <summary>
/// Creates an instance of the quantity from a specified value and unit.
/// </summary>
Expand All @@ -157,10 +185,14 @@ public interface IQuantity<TSelf, TUnitType> : IQuantityOfType<TSelf>, IQuantity

static TSelf IQuantityOfType<TSelf>.Create(double value, UnitKey unit) => TSelf.From(value, unit.ToUnit<TUnitType>());

static QuantityInfo IQuantityOfType<TSelf>.Info => TSelf.Info;

#pragma warning disable CS0618 // Type or member is obsolete
QuantityInfo<TUnitType> IQuantity<TUnitType>.QuantityInfo
{
get => QuantityInfo;
}
#pragma warning restore CS0618

IQuantity<TUnitType> IQuantity<TUnitType>.ToUnit(TUnitType unit)
{
Expand Down
11 changes: 9 additions & 2 deletions UnitsNet/QuantityDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ internal readonly struct AbbreviationDisplay
public AbbreviationDisplay(IQuantity quantity)
{
_quantity = quantity;
#pragma warning disable CS0618 // IQuantity.QuantityInfo: debug proxy must work for custom quantities not registered in UnitsNetSetup.Default.
QuantityInfo quantityQuantityInfo = quantity.QuantityInfo;
#pragma warning restore CS0618
IQuantity baseQuantity = quantity.ToUnit(quantityQuantityInfo.BaseUnitInfo.Value);
Conversions = quantityQuantityInfo.UnitInfos.Select(x => new ConvertedQuantity(baseQuantity, x)).ToArray();
}
Expand Down Expand Up @@ -70,8 +72,11 @@ internal readonly struct UnitDisplay
public UnitDisplay(IQuantity quantity)
{
Unit = quantity.Unit;
IQuantity baseQuantity = quantity.ToUnit(quantity.QuantityInfo.BaseUnitInfo.Value);
Conversions = quantity.QuantityInfo.UnitInfos.Select(x => new ConvertedQuantity(baseQuantity, x.Value)).ToArray();
#pragma warning disable CS0618 // IQuantity.QuantityInfo: debug proxy must work for custom quantities not registered in UnitsNetSetup.Default.
QuantityInfo info = quantity.QuantityInfo;
#pragma warning restore CS0618
IQuantity baseQuantity = quantity.ToUnit(info.BaseUnitInfo.Value);
Conversions = info.UnitInfos.Select(x => new ConvertedQuantity(baseQuantity, x.Value)).ToArray();
}

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
Expand Down Expand Up @@ -110,7 +115,9 @@ internal readonly struct QuantityConvertor
public QuantityConvertor(IQuantity quantity)
{
QuantityToString = new StringFormatsDisplay(quantity);
#pragma warning disable CS0618 // IQuantity.QuantityInfo: debug proxy must work for custom quantities not registered in UnitsNetSetup.Default.
QuantityInfo quantityQuantityInfo = quantity.QuantityInfo;
#pragma warning restore CS0618
IQuantity baseQuantity = quantity.ToUnit(quantityQuantityInfo.BaseUnitInfo.Value);
QuantityToUnit = quantityQuantityInfo.UnitInfos.Select(x => new ConvertedQuantity(baseQuantity.ToUnit(x.Value), x)).ToArray();
}
Expand Down
2 changes: 2 additions & 0 deletions UnitsNet/QuantityTypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,10 @@ private static TAttribute? GetAttribute<
// Ensure the attribute's unit is compatible with this converter's quantity.
if (attribute?.UnitType != null)
{
#pragma warning disable CS0618 // IQuantity.QuantityInfo is obsolete on .NET 5+; use it here so consumers can author custom quantities (e.g. HowMuch in tests) without registering them in UnitsNetSetup.Default.
string converterQuantityName = default(TQuantity).QuantityInfo.Name;
string attributeQuantityName = Quantity.From(1, attribute.UnitType).QuantityInfo.Name;
#pragma warning restore CS0618
if (converterQuantityName != attributeQuantityName)
{
throw new ArgumentException($"The {attribute.GetType()}'s UnitType [{attribute.UnitType}] is not compatible with the converter's quantity [{converterQuantityName}].");
Expand Down
Loading