Skip to content

Commit 5db5782

Browse files
Ted-Jin-Labangularsenclaude
authored
🎉Add new NumberExtensionsCS14 nuget package (#1620)
Fixes #1619 Add new project `NumberExtensionsCS14` to use the C#14 feature `extension members` for making `5.Meters` work. Please merge after C#14 is officially released. --------- Co-authored-by: Andreas Gullberg Larsen <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent bde4d1a commit 5db5782

File tree

267 files changed

+30351
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

267 files changed

+30351
-3
lines changed

Build/build-functions.psm1

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ function Start-Tests {
9090
$projectPaths = @(
9191
"UnitsNet.Tests\UnitsNet.Tests.csproj",
9292
"UnitsNet.NumberExtensions.Tests\UnitsNet.NumberExtensions.Tests.csproj",
93+
"UnitsNet.NumberExtensions.CS14.Tests\UnitsNet.NumberExtensions.CS14.Tests.csproj",
9394
"UnitsNet.Serialization.JsonNet.Tests\UnitsNet.Serialization.JsonNet.Tests.csproj"
9495
)
9596

@@ -129,7 +130,8 @@ function Start-PackNugets {
129130
$projectPaths = @(
130131
"UnitsNet\UnitsNet.csproj",
131132
"UnitsNet.Serialization.JsonNet\UnitsNet.Serialization.JsonNet.csproj",
132-
"UnitsNet.NumberExtensions\UnitsNet.NumberExtensions.csproj"
133+
"UnitsNet.NumberExtensions\UnitsNet.NumberExtensions.csproj",
134+
"UnitsNet.NumberExtensions.CS14\UnitsNet.NumberExtensions.CS14.csproj"
133135
)
134136

135137
write-host -foreground blue "Pack nugets (dotnet CLI)...`n---"
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System;
2+
using CodeGen.JsonTypes;
3+
4+
namespace CodeGen.Generators.UnitsNetGen
5+
{
6+
internal class NumberExtensionsCS14Generator(Quantity quantity) : GeneratorBase
7+
{
8+
private readonly Quantity _quantity = quantity ?? throw new ArgumentNullException(nameof(quantity));
9+
private readonly Unit[] _units = quantity.Units;
10+
private readonly string _quantityName = quantity.Name;
11+
12+
public string Generate()
13+
{
14+
Writer.WL(GeneratedFileHeader);
15+
16+
Writer.WL(
17+
$@"
18+
using System;
19+
20+
#if NET7_0_OR_GREATER
21+
using System.Numerics;
22+
#endif
23+
24+
#nullable enable
25+
26+
namespace UnitsNet.NumberExtensions.NumberTo{_quantityName}
27+
{{
28+
/// <summary>
29+
/// A number to {_quantityName} Extensions
30+
/// </summary>");
31+
32+
Writer.WLIfText(1, GetObsoleteAttributeOrNull(_quantity));
33+
Writer.WL(@$"
34+
public static class NumberTo{_quantityName}Extensions
35+
{{");
36+
37+
Writer.WL(@"
38+
#pragma warning disable CS1591
39+
extension<T>(T value)
40+
#pragma warning restore CS1591
41+
where T : notnull
42+
#if NET7_0_OR_GREATER
43+
, INumber<T>
44+
#else
45+
, IConvertible
46+
#endif
47+
{");
48+
49+
50+
foreach (var unit in _units)
51+
{
52+
if (unit.SkipConversionGeneration)
53+
continue;
54+
55+
Writer.WL(3, $@"
56+
/// <inheritdoc cref=""{_quantityName}.From{unit.PluralName}(double)"" />");
57+
58+
// Include obsolete text from the quantity per extension method, to make it visible when the class is not explicitly referenced in code.
59+
Writer.WLIfText(3, GetObsoleteAttributeOrNull(unit.ObsoleteText ?? _quantity.ObsoleteText));
60+
61+
Writer.WL(3, $@"public {_quantityName} {unit.PluralName}
62+
#if NET7_0_OR_GREATER
63+
=> {_quantityName}.From{unit.PluralName}(double.CreateChecked(value));
64+
#else
65+
=> {_quantityName}.From{unit.PluralName}(value.ToDouble(null));
66+
#endif
67+
");
68+
}
69+
70+
Writer.WL(2, @"}
71+
}
72+
}");
73+
return Writer.ToString();
74+
}
75+
76+
/// <inheritdoc cref="GetObsoleteAttributeOrNull(string)"/>
77+
private static string? GetObsoleteAttributeOrNull(Quantity quantity) => GetObsoleteAttributeOrNull(quantity.ObsoleteText);
78+
79+
private static string? GetObsoleteAttributeOrNull(string? obsoleteText) =>
80+
string.IsNullOrWhiteSpace(obsoleteText) ? null : $"[Obsolete(\"{obsoleteText}\")]";
81+
}
82+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System;
2+
using CodeGen.JsonTypes;
3+
4+
namespace CodeGen.Generators.UnitsNetGen
5+
{
6+
internal class NumberExtensionsCS14TestClassGenerator : GeneratorBase
7+
{
8+
private readonly Unit[] _units;
9+
private readonly string _quantityName;
10+
11+
public NumberExtensionsCS14TestClassGenerator(Quantity quantity)
12+
{
13+
if (quantity is null) throw new ArgumentNullException(nameof(quantity));
14+
15+
_units = quantity.Units;
16+
_quantityName = quantity.Name;
17+
}
18+
19+
public string Generate()
20+
{
21+
Writer.WL(GeneratedFileHeader);
22+
23+
Writer.WL(
24+
$@"
25+
using UnitsNet.NumberExtensions.NumberTo{_quantityName};
26+
using Xunit;
27+
28+
namespace UnitsNet.Tests
29+
{{
30+
public class NumberTo{_quantityName}ExtensionsTests
31+
{{");
32+
33+
foreach (var unit in _units)
34+
{
35+
if (unit.SkipConversionGeneration)
36+
continue;
37+
38+
Writer.WL(2, $@"
39+
[Fact]");
40+
41+
Writer.WL(2, $@"public void NumberTo{unit.PluralName}Test() =>
42+
Assert.Equal({_quantityName}.From{unit.PluralName}(2), 2.{unit.PluralName});
43+
");
44+
}
45+
46+
Writer.WL(1, @"}
47+
}");
48+
return Writer.ToString();
49+
}
50+
}
51+
}

CodeGen/Generators/UnitsNetGenerator.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,17 @@ public static void Generate(string rootDir, Quantity[] quantities, QuantityNameT
3939
var outputDir = $"{rootDir}/UnitsNet/GeneratedCode";
4040
var extensionsOutputDir = $"{rootDir}/UnitsNet.NumberExtensions/GeneratedCode";
4141
var extensionsTestOutputDir = $"{rootDir}/UnitsNet.NumberExtensions.Tests/GeneratedCode";
42+
var extensionsCs14OutputDir = $"{rootDir}/UnitsNet.NumberExtensions.CS14/GeneratedCode";
43+
var extensionsCs14TestOutputDir = $"{rootDir}/UnitsNet.NumberExtensions.CS14.Tests/GeneratedCode";
4244
var testProjectDir = $"{rootDir}/UnitsNet.Tests";
4345

4446
// Ensure output directories exist
4547
Directory.CreateDirectory($"{outputDir}/Quantities");
4648
Directory.CreateDirectory($"{outputDir}/Units");
4749
Directory.CreateDirectory($"{extensionsOutputDir}");
4850
Directory.CreateDirectory($"{extensionsTestOutputDir}");
51+
Directory.CreateDirectory($"{extensionsCs14OutputDir}");
52+
Directory.CreateDirectory($"{extensionsCs14TestOutputDir}");
4953
Directory.CreateDirectory($"{testProjectDir}/GeneratedCode");
5054
Directory.CreateDirectory($"{testProjectDir}/GeneratedCode/TestsBase");
5155
Directory.CreateDirectory($"{testProjectDir}/GeneratedCode/QuantityTests");
@@ -58,6 +62,8 @@ public static void Generate(string rootDir, Quantity[] quantities, QuantityNameT
5862
GenerateUnitType(quantity, $"{outputDir}/Units/{quantity.Name}Unit.g.cs", unitEnumValues);
5963
GenerateNumberToExtensions(quantity, $"{extensionsOutputDir}/NumberTo{quantity.Name}Extensions.g.cs");
6064
GenerateNumberToExtensionsTestClass(quantity, $"{extensionsTestOutputDir}/NumberTo{quantity.Name}ExtensionsTest.g.cs");
65+
GenerateNumberToExtensionsCS14(quantity, $"{extensionsCs14OutputDir}/NumberTo{quantity.Name}Extensions.g.cs");
66+
GenerateNumberToExtensionsCS14TestClass(quantity, $"{extensionsCs14TestOutputDir}/NumberTo{quantity.Name}ExtensionsTest.g.cs");
6167

6268
// Example: CustomCode/Quantities/LengthTests inherits GeneratedCode/TestsBase/LengthTestsBase
6369
// This way when new units are added to the quantity JSON definition, we auto-generate the new
@@ -107,6 +113,18 @@ private static void GenerateNumberToExtensionsTestClass(Quantity quantity, strin
107113
File.WriteAllText(filePath, content);
108114
}
109115

116+
private static void GenerateNumberToExtensionsCS14(Quantity quantity, string filePath)
117+
{
118+
var content = new NumberExtensionsCS14Generator(quantity).Generate();
119+
File.WriteAllText(filePath, content);
120+
}
121+
122+
private static void GenerateNumberToExtensionsCS14TestClass(Quantity quantity, string filePath)
123+
{
124+
var content = new NumberExtensionsCS14TestClassGenerator(quantity).Generate();
125+
File.WriteAllText(filePath, content);
126+
}
127+
110128
private static void GenerateUnitType(Quantity quantity, string filePath, UnitEnumNameToValue unitEnumValues)
111129
{
112130
var content = new UnitTypeGenerator(quantity, unitEnumValues).Generate();

README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,49 @@ dotnet add package UnitsNet
4545

4646
or go to [NuGet Gallery | UnitsNet](https://www.nuget.org/packages/UnitsNet) for detailed instructions.
4747

48-
#### Build Targets
48+
### Build Targets
4949

5050
* .NET Standard 2.0
51+
* .NET 8.0 (LTS)
52+
* .NET 9.0 (latest stable)
53+
* .NET 10.0 (preview)
5154
* [.NET nanoFramework](https://www.nanoframework.net/)
5255

56+
57+
### Extension Packages
58+
59+
#### UnitsNet.NumberExtensions.CS14 (C# 14 Extension Members)
60+
61+
For C# 14 projects, use the new extension members syntax (no parentheses):
62+
63+
```bash
64+
dotnet add package UnitsNet.NumberExtensions.CS14
65+
```
66+
67+
```C#
68+
using UnitsNet.NumberExtensions.NumberToLength;
69+
70+
// C# 14 extension members syntax, without parantheses
71+
Length distance = 5.Meters; // Instead of Length.FromMeters(5)
72+
```
73+
74+
> **Note:** Requires '<LangVersion>preview</LangVersion>' and .NET 10 SDK preview for now.
75+
76+
#### UnitsNet.NumberExtensions (Classic)
77+
78+
For C# 13 and lower (.NET SDK 9 or lower), use the classic extension methods:
79+
80+
```bash
81+
dotnet add package UnitsNet.NumberExtensions
82+
```
83+
84+
```C#
85+
using UnitsNet.NumberExtensions.NumberToLength;
86+
87+
// Classic extension methods, with parentheses
88+
Length distance = 5.Meters(); // Instead of Length.FromMeters(5)
89+
```
90+
5391
### Static Typing
5492

5593
```C#

UnitsNet.NumberExtensions.CS14.Tests/GeneratedCode/NumberToAbsorbedDoseOfIonizingRadiationExtensionsTest.g.cs

Lines changed: 96 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)