Skip to content

Commit 2a60bf9

Browse files
angularsenclaude
andauthored
Add IQuantity.UnitInfo convenience property (#1649)
## Summary - Adds `IQuantity.UnitInfo` default interface member on .NET 5+ targets, so consumers can write `quantity.UnitInfo` instead of `quantity.QuantityInfo[quantity.UnitKey]` - Adds typed `IQuantity<TUnitType>.UnitInfo` returning `UnitInfo<TUnitType>` on .NET 5+ - Adds `GetUnitInfo()` and `GetUnitInfo<TUnit>()` extension methods on `netstandard2.0` for the same functionality ## Motivation Getting `UnitInfo` from a quantity instance currently requires the verbose `quantity.QuantityInfo[quantity.UnitKey]`. This is a common operation, especially when chaining with APIs like `UnitAbbreviationsCache` that benefit from having `UnitInfo` directly (see #1067). ## Design decisions ### TFM fragmentation The extension methods are gated behind `#if !NET` so that .NET 5+ consumers only see the cleaner property syntax in IntelliSense. Library authors who multi-target can use `quantity.QuantityInfo[quantity.UnitKey]` which works on all targets, or write a one-line wrapper. If this turns out to be a real pain point, removing the `#if` guard is a non-breaking one-line change. ### Extension method tests The test project targets `net8.0;net9.0;net10.0` only, so `#if !NET` code is never compiled in tests. The extension methods are trivial one-liner wrappers over the same indexer call that the default interface members use, so they are effectively covered by the property tests. ## Test plan - [x] `dotnet build UnitsNet/UnitsNet.csproj` — 0 errors across all 4 target frameworks - [x] New tests pass on net8.0, net9.0, net10.0: - `UnitInfo_ReturnsUnitInfoForQuantityUnit` — non-base unit via `IQuantity` - `UnitInfo_Zero_ReturnsBaseUnitInfo` — `.Zero` instance - `UnitInfo_TypedQuantity_ReturnsTypedUnitInfo` — typed `IQuantity<LengthUnit>` - `UnitInfo_MatchesUnit` — `Assert.All` across all quantities 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 414fe57 commit 2a60bf9

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed

UnitsNet.Tests/CustomCode/IQuantityTests.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,48 @@ public void ToUnit_UnitSystem_ThrowsArgumentNullExceptionIfNull()
5959
});
6060
}
6161

62+
[Fact]
63+
public void UnitInfo_ReturnsUnitInfoForQuantityUnit()
64+
{
65+
var length = new Length(3.0, LengthUnit.Centimeter);
66+
IQuantity quantity = length;
67+
68+
UnitInfo unitInfo = quantity.UnitInfo;
69+
70+
Assert.Equal(nameof(LengthUnit.Centimeter), unitInfo.Name);
71+
Assert.Equal(quantity.UnitKey, unitInfo.UnitKey);
72+
}
73+
74+
[Fact]
75+
public void UnitInfo_Zero_ReturnsBaseUnitInfo()
76+
{
77+
IQuantity quantity = Length.Info.Zero;
78+
79+
UnitInfo unitInfo = quantity.UnitInfo;
80+
81+
Assert.Equal(Length.Info.BaseUnitInfo.UnitKey, unitInfo.UnitKey);
82+
}
83+
84+
[Fact]
85+
public void UnitInfo_TypedQuantity_ReturnsTypedUnitInfo()
86+
{
87+
IQuantity<LengthUnit> quantity = new Length(3.0, LengthUnit.Centimeter);
88+
89+
UnitInfo<LengthUnit> unitInfo = quantity.UnitInfo;
90+
91+
Assert.Equal(LengthUnit.Centimeter, unitInfo.Value);
92+
Assert.Equal(nameof(LengthUnit.Centimeter), unitInfo.Name);
93+
}
94+
95+
[Fact]
96+
public void UnitInfo_MatchesUnit()
97+
{
98+
Assert.All(Quantity.Infos.Select(x => x.Zero), quantity =>
99+
{
100+
Assert.Equal(quantity.Unit, quantity.UnitInfo.Value);
101+
});
102+
}
103+
62104
[Fact]
63105
public void ToUnit_UnitSystem_ThrowsArgumentExceptionIfNotSupported()
64106
{

UnitsNet/Extensions/QuantityExtensions.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,38 @@ namespace UnitsNet;
1111
/// </summary>
1212
public static class QuantityExtensions
1313
{
14+
#if !NET
15+
/// <summary>
16+
/// Gets the <see cref="UnitInfo"/> for the unit this quantity was constructed with.
17+
/// </summary>
18+
/// <param name="quantity">The quantity.</param>
19+
/// <returns>The <see cref="UnitInfo"/> for the quantity's unit.</returns>
20+
/// <remarks>
21+
/// On .NET 5+ targets, this is available as a default interface member property
22+
/// <c>IQuantity.UnitInfo</c> instead.
23+
/// </remarks>
24+
public static UnitInfo GetUnitInfo(this IQuantity quantity)
25+
{
26+
return quantity.QuantityInfo[quantity.UnitKey];
27+
}
28+
29+
/// <summary>
30+
/// Gets the <see cref="UnitInfo{TUnit}"/> for the unit this quantity was constructed with.
31+
/// </summary>
32+
/// <typeparam name="TUnit">The unit enum type.</typeparam>
33+
/// <param name="quantity">The quantity.</param>
34+
/// <returns>The <see cref="UnitInfo{TUnit}"/> for the quantity's unit.</returns>
35+
/// <remarks>
36+
/// On .NET 5+ targets, this is available as a default interface member property
37+
/// <c>IQuantity&lt;TUnitType&gt;.UnitInfo</c> instead.
38+
/// </remarks>
39+
public static UnitInfo<TUnit> GetUnitInfo<TUnit>(this IQuantity<TUnit> quantity)
40+
where TUnit : struct, Enum
41+
{
42+
return quantity.QuantityInfo[quantity.Unit];
43+
}
44+
#endif
45+
1446
/// <inheritdoc cref="IQuantity.As(UnitKey)" />
1547
/// <remarks>This should be using UnitConverter.Default.ConvertValue(quantity, toUnit) </remarks>
1648
internal static double GetValue<TQuantity>(this TQuantity quantity, UnitKey toUnit)

UnitsNet/IQuantity.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ public interface IQuantity : IFormattable
5858
/// as it avoids the boxing that would normally occur when casting the enum to <see cref="Enum" />.
5959
/// </remarks>
6060
UnitKey UnitKey { get; }
61+
62+
#if NET
63+
/// <summary>
64+
/// Gets the <see cref="UnitsNet.UnitInfo"/> for the unit this quantity was constructed with.
65+
/// </summary>
66+
/// <remarks>
67+
/// On targets that do not support default interface members (e.g. netstandard2.0),
68+
/// use the <c>GetUnitInfo()</c> extension method from <see cref="QuantityExtensions"/> instead.
69+
/// </remarks>
70+
UnitInfo UnitInfo => QuantityInfo[UnitKey];
71+
#endif
6172
}
6273

6374
/// <summary>
@@ -94,8 +105,13 @@ public interface IQuantity<TUnitType> : IQuantity
94105

95106
#if NET
96107

108+
/// <inheritdoc cref="IQuantity.UnitInfo"/>
109+
new UnitInfo<TUnitType> UnitInfo => QuantityInfo[Unit];
110+
97111
#region Implementation of IQuantity
98112

113+
UnitInfo IQuantity.UnitInfo => UnitInfo;
114+
99115
QuantityInfo IQuantity.QuantityInfo
100116
{
101117
get => QuantityInfo;

0 commit comments

Comments
 (0)