Skip to content

Commit 30cb110

Browse files
authored
Fix custom quantity support in QuantityInfo (#896)
Fixes #895 Replace cache of internal unit enum types with constructor parameter Remove obsolete constructors (which did not work for custom quantities anyway)
1 parent d2dc263 commit 30cb110

File tree

3 files changed

+87
-29
lines changed

3 files changed

+87
-29
lines changed

UnitsNet.Tests/CustomQuantities/HowMuch.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ public HowMuch(double value, HowMuchUnit unit)
2626
public QuantityType Type => QuantityType.Undefined;
2727
public BaseDimensions Dimensions => BaseDimensions.Dimensionless;
2828

29-
public QuantityInfo QuantityInfo => new QuantityInfo("HowMuch",
29+
public QuantityInfo QuantityInfo => new QuantityInfo(
30+
nameof(HowMuch),
31+
typeof(HowMuchUnit),
3032
new UnitInfo[]
3133
{
3234
new UnitInfo<HowMuchUnit>(HowMuchUnit.Some, BaseUnits.Undefined),

UnitsNet.Tests/QuantityInfoTest.cs

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Diagnostics.CodeAnalysis;
66
using System.Linq;
7+
using UnitsNet.Tests.CustomQuantities;
78
using UnitsNet.Units;
89
using Xunit;
910

@@ -23,9 +24,62 @@ public void Constructor_AssignsProperties()
2324
var expectedQuantityType = QuantityType.Length;
2425
var expectedBaseDimensions = Length.BaseDimensions;
2526

26-
var info = new QuantityInfo(expectedQuantityType, expectedUnitInfos,
27+
var info = new QuantityInfo(nameof(Length), typeof(LengthUnit), expectedUnitInfos,
28+
expectedBaseUnit, expectedZero, expectedBaseDimensions, QuantityType.Length);
29+
30+
Assert.Equal(expectedZero, info.Zero);
31+
Assert.Equal("Length", info.Name);
32+
Assert.Equal(expectedUnitInfos, info.UnitInfos);
33+
Assert.Equal(expectedQuantityType, info.QuantityType);
34+
Assert.Equal(expectedBaseDimensions, info.BaseDimensions);
35+
36+
// Obsolete members
37+
Assert.Equal( expectedBaseUnit, info.BaseUnit );
38+
Assert.Equal( new[] { "Centimeter", "Kilometer" }, info.UnitNames );
39+
}
40+
41+
[Fact]
42+
public void Constructor_AssignsPropertiesForCustomQuantity()
43+
{
44+
var expectedZero = new HowMuch(10, HowMuchUnit.Some);
45+
var expectedUnitInfos = new UnitInfo[]
46+
{
47+
new UnitInfo(HowMuchUnit.Some, BaseUnits.Undefined),
48+
new UnitInfo(HowMuchUnit.ATon, BaseUnits.Undefined),
49+
new UnitInfo(HowMuchUnit.AShitTon, BaseUnits.Undefined)
50+
};
51+
var expectedBaseUnit = HowMuchUnit.Some;
52+
var expectedQuantityType = QuantityType.Undefined;
53+
var expectedBaseDimensions = BaseDimensions.Dimensionless;
54+
55+
var info = new QuantityInfo(nameof(HowMuch), typeof(HowMuchUnit), expectedUnitInfos,
2756
expectedBaseUnit, expectedZero, expectedBaseDimensions);
2857

58+
Assert.Equal(expectedZero, info.Zero);
59+
Assert.Equal(nameof(HowMuch), info.Name);
60+
Assert.Equal(expectedUnitInfos, info.UnitInfos);
61+
Assert.Equal(expectedQuantityType, info.QuantityType);
62+
Assert.Equal(expectedBaseDimensions, info.BaseDimensions);
63+
64+
// Obsolete members
65+
Assert.Equal( expectedBaseUnit, info.BaseUnit );
66+
Assert.Equal(new[] {nameof(HowMuchUnit.Some), nameof(HowMuchUnit.ATon), nameof(HowMuchUnit.AShitTon)}, info.UnitNames);
67+
}
68+
69+
[Fact]
70+
public void ObsoleteConstructor_AssignsProperties()
71+
{
72+
var expectedZero = Length.FromCentimeters(10);
73+
var expectedUnitInfos = new UnitInfo[]{
74+
new UnitInfo(LengthUnit.Centimeter, new BaseUnits(LengthUnit.Centimeter)),
75+
new UnitInfo(LengthUnit.Kilometer, new BaseUnits(LengthUnit.Kilometer))
76+
};
77+
var expectedBaseUnit = LengthUnit.Centimeter;
78+
var expectedQuantityType = QuantityType.Length;
79+
var expectedBaseDimensions = Length.BaseDimensions;
80+
81+
var info = new QuantityInfo(QuantityType.Length, expectedUnitInfos, expectedBaseUnit, expectedZero, expectedBaseDimensions);
82+
2983
Assert.Equal(expectedZero, info.Zero);
3084
Assert.Equal("Length", info.Name);
3185
Assert.Equal(expectedUnitInfos, info.UnitInfos);
@@ -37,6 +91,7 @@ public void Constructor_AssignsProperties()
3791
Assert.Equal( new[] { "Centimeter", "Kilometer" }, info.UnitNames );
3892
}
3993

94+
4095
[Fact]
4196
public void GenericsConstructor_AssignsProperties()
4297
{
@@ -49,8 +104,8 @@ public void GenericsConstructor_AssignsProperties()
49104
var expectedQuantityType = QuantityType.Length;
50105
var expectedBaseDimensions = Length.BaseDimensions;
51106

52-
var info = new QuantityInfo<LengthUnit>(expectedQuantityType, expectedUnitInfos,
53-
expectedBaseUnit, expectedZero, expectedBaseDimensions);
107+
var info = new QuantityInfo<LengthUnit>(nameof(Length), expectedUnitInfos,
108+
expectedBaseUnit, expectedZero, expectedBaseDimensions, expectedQuantityType);
54109
Assert.Equal(expectedZero, info.Zero);
55110
Assert.Equal("Length", info.Name);
56111
Assert.Equal(expectedUnitInfos, info.UnitInfos);
@@ -66,62 +121,62 @@ public void GenericsConstructor_AssignsProperties()
66121
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
67122
public void Constructor_GivenNullAsUnitInfos_ThrowsArgumentNullException()
68123
{
69-
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(QuantityType.Length,
70-
null, Length.BaseUnit, Length.Zero, Length.BaseDimensions));
124+
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(nameof(Length), typeof(LengthUnit),
125+
null, Length.BaseUnit, Length.Zero, Length.BaseDimensions, QuantityType.Length));
71126
}
72127

73128
[Fact]
74129
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
75130
public void GenericsConstructor_GivenNullAsUnitInfos_ThrowsArgumentNullException()
76131
{
77-
Assert.Throws<ArgumentNullException>(() => new QuantityInfo<LengthUnit>(QuantityType.Length,
78-
null, Length.BaseUnit, Length.Zero, Length.BaseDimensions));
132+
Assert.Throws<ArgumentNullException>(() => new QuantityInfo<LengthUnit>(nameof(Length),
133+
null, Length.BaseUnit, Length.Zero, Length.BaseDimensions, QuantityType.Length));
79134
}
80135

81136
[Fact]
82137
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
83138
public void Constructor_GivenNullAsBaseUnit_ThrowsArgumentNullException()
84139
{
85-
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(QuantityType.Length,
86-
Length.Info.UnitInfos, null, Length.Zero, Length.BaseDimensions));
140+
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(nameof(Length), typeof(LengthUnit),
141+
Length.Info.UnitInfos, null, Length.Zero, Length.BaseDimensions, QuantityType.Length));
87142
}
88143

89144
[Fact]
90145
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
91146
public void Constructor_GivenNullAsZero_ThrowsArgumentNullException()
92147
{
93-
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(QuantityType.Length,
94-
Length.Info.UnitInfos, Length.BaseUnit, null, Length.BaseDimensions));
148+
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(nameof(Length), typeof(LengthUnit),
149+
Length.Info.UnitInfos, Length.BaseUnit, null, Length.BaseDimensions, QuantityType.Length));
95150
}
96151

97152
[Fact]
98153
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
99154
public void GenericsConstructor_GivenNullAsZero_ThrowsArgumentNullException()
100155
{
101-
Assert.Throws<ArgumentNullException>(() => new QuantityInfo<LengthUnit>(QuantityType.Length,
102-
Length.Info.UnitInfos, Length.BaseUnit, null, Length.BaseDimensions));
156+
Assert.Throws<ArgumentNullException>(() => new QuantityInfo<LengthUnit>(nameof(Length),
157+
Length.Info.UnitInfos, Length.BaseUnit, null, Length.BaseDimensions, QuantityType.Length));
103158
}
104159

105160
[Fact]
106161
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
107162
public void Constructor_GivenNullAsBaseDimensions_ThrowsArgumentNullException()
108163
{
109-
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(QuantityType.Length,
110-
Length.Info.UnitInfos, Length.BaseUnit, Length.Zero, null));
164+
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(nameof(Length), typeof(LengthUnit),
165+
Length.Info.UnitInfos, Length.BaseUnit, Length.Zero, null, QuantityType.Length));
111166
}
112167

113168
[Fact]
114169
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
115170
public void GenericsConstructor_GivenNullAsBaseDimensions_ThrowsArgumentNullException()
116171
{
117-
Assert.Throws<ArgumentNullException>(() => new QuantityInfo<LengthUnit>(QuantityType.Length,
118-
Length.Info.UnitInfos, Length.BaseUnit, Length.Zero, null));
172+
Assert.Throws<ArgumentNullException>(() => new QuantityInfo<LengthUnit>(nameof(Length),
173+
Length.Info.UnitInfos, Length.BaseUnit, Length.Zero, null, QuantityType.Length));
119174
}
120175
[Fact]
121176
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
122177
public void Constructor2_GivenNullAsUnitInfos_ThrowsArgumentNullException()
123178
{
124-
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(Length.Info.Name,
179+
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(Length.Info.Name, typeof(LengthUnit),
125180
null, Length.BaseUnit, Length.Zero, Length.BaseDimensions));
126181
}
127182

@@ -137,15 +192,15 @@ public void GenericsConstructor2_GivenNullAsUnitInfos_ThrowsArgumentNullExceptio
137192
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
138193
public void Constructor2_GivenNullAsBaseUnit_ThrowsArgumentNullException()
139194
{
140-
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(Length.Info.Name,
195+
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(Length.Info.Name, typeof(LengthUnit),
141196
Length.Info.UnitInfos, null, Length.Zero, Length.BaseDimensions));
142197
}
143198

144199
[Fact]
145200
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
146201
public void Constructor2_GivenNullAsZero_ThrowsArgumentNullException()
147202
{
148-
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(Length.Info.Name,
203+
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(Length.Info.Name, typeof(LengthUnit),
149204
Length.Info.UnitInfos, Length.BaseUnit, null, Length.BaseDimensions));
150205
}
151206

@@ -161,7 +216,7 @@ public void GenericsConstructor2_GivenNullAsZero_ThrowsArgumentNullException()
161216
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
162217
public void Constructor2_GivenNullAsBaseDimensions_ThrowsArgumentNullException()
163218
{
164-
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(Length.Info.Name,
219+
Assert.Throws<ArgumentNullException>(() => new QuantityInfo(Length.Info.Name, typeof(LengthUnit),
165220
Length.Info.UnitInfos, Length.BaseUnit, Length.Zero, null));
166221
}
167222

UnitsNet/QuantityInfo.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ public class QuantityInfo
2323
{
2424
private static readonly string UnitEnumNamespace = typeof(LengthUnit).Namespace;
2525

26-
private static readonly Type[] UnitEnumTypes = typeof(Length)
26+
private static readonly Dictionary<string, Type> UnitEnumTypes = typeof(Length)
2727
.Wrap()
2828
.Assembly
2929
.GetExportedTypes()
3030
.Where(t => t.Wrap().IsEnum && t.Namespace == UnitEnumNamespace && t.Name.EndsWith("Unit"))
31-
.ToArray();
31+
.ToDictionary(t => t.Name, t => t);
3232

3333
/// <summary>
3434
/// Constructs an instance.
@@ -42,31 +42,32 @@ public class QuantityInfo
4242
/// <exception cref="ArgumentNullException">If units -or- baseUnit -or- zero -or- baseDimensions is null.</exception>
4343
[Obsolete("QuantityType will be removed in the future. Use QuantityInfo(string, UnitInfo[], Enum, IQuantity, BaseDimensions) instead.")]
4444
public QuantityInfo(QuantityType quantityType, [NotNull] UnitInfo[] unitInfos, [NotNull] Enum baseUnit, [NotNull] IQuantity zero, [NotNull] BaseDimensions baseDimensions)
45-
: this(quantityType.ToString(), unitInfos, baseUnit, zero, baseDimensions, quantityType)
45+
: this(quantityType.ToString(), UnitEnumTypes[$"{quantityType}Unit"], unitInfos, baseUnit, zero, baseDimensions, quantityType)
4646
{
4747
}
4848

4949
/// <summary>
5050
/// Constructs an instance.
5151
/// </summary>
5252
/// <param name="name">Name of the quantity.</param>
53+
/// <param name="unitType">The unit enum type, such as <see cref="LengthUnit" />.</param>
5354
/// <param name="unitInfos">The information about the units for this quantity.</param>
5455
/// <param name="baseUnit">The base unit enum value.</param>
5556
/// <param name="zero">The zero quantity.</param>
5657
/// <param name="baseDimensions">The base dimensions of the quantity.</param>
5758
/// <param name="quantityType">The the quantity type. Defaults to Undefined.</param>
5859
/// <exception cref="ArgumentException">Quantity type can not be undefined.</exception>
5960
/// <exception cref="ArgumentNullException">If units -or- baseUnit -or- zero -or- baseDimensions is null.</exception>
60-
public QuantityInfo([NotNull] string name, [NotNull] UnitInfo[] unitInfos, [NotNull] Enum baseUnit, [NotNull] IQuantity zero, [NotNull] BaseDimensions baseDimensions,
61+
public QuantityInfo([NotNull] string name, Type unitType, [NotNull] UnitInfo[] unitInfos, [NotNull] Enum baseUnit, [NotNull] IQuantity zero, [NotNull] BaseDimensions baseDimensions,
6162
QuantityType quantityType = QuantityType.Undefined)
6263
{
6364
if(baseUnit == null) throw new ArgumentNullException(nameof(baseUnit));
6465

6566
BaseDimensions = baseDimensions ?? throw new ArgumentNullException(nameof(baseDimensions));
6667
Zero = zero ?? throw new ArgumentNullException(nameof(zero));
6768

68-
Name = name;
69-
UnitType = UnitEnumTypes.First(t => t.Name == $"{name}Unit");
69+
Name = name ?? throw new ArgumentNullException(nameof(name));
70+
UnitType = unitType ?? throw new ArgumentNullException(nameof(unitType));
7071
UnitInfos = unitInfos ?? throw new ArgumentNullException(nameof(unitInfos));
7172
BaseUnitInfo = UnitInfos.First(unitInfo => unitInfo.Value.Equals(baseUnit));
7273
Zero = zero ?? throw new ArgumentNullException(nameof(zero));
@@ -203,7 +204,7 @@ public QuantityInfo(QuantityType quantityType, UnitInfo<TUnit>[] unitInfos, TUni
203204
/// <inheritdoc />
204205
public QuantityInfo(string name, UnitInfo<TUnit>[] unitInfos, TUnit baseUnit, IQuantity<TUnit> zero, BaseDimensions baseDimensions,
205206
QuantityType quantityType = QuantityType.Undefined)
206-
: base(name, unitInfos.ToArray<UnitInfo>(), baseUnit, zero, baseDimensions, quantityType)
207+
: base(name, typeof(TUnit), unitInfos.ToArray<UnitInfo>(), baseUnit, zero, baseDimensions, quantityType)
207208
{
208209
Zero = zero;
209210
UnitInfos = unitInfos ?? throw new ArgumentNullException(nameof(unitInfos));

0 commit comments

Comments
 (0)