Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Experiment with Generic Math in .NET6 #984

Closed
wants to merge 2 commits into from
Closed
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
16 changes: 16 additions & 0 deletions ConsoleNet6/ConsoleNet6.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<!-- .NET6 Experimental! -->
<ItemGroup>
<PackageReference Include="System.Runtime.Experimental" Version="6.0.0-preview.7.21377.19" />
</ItemGroup>

</Project>
15 changes: 15 additions & 0 deletions ConsoleNet6/IQuantity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed under MIT No Attribution, see LICENSE file at the root.
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.

namespace ConsoleNet6
{
public interface IQuantity<TQuantity> :
IAdditionOperators<TQuantity, TQuantity, TQuantity>,
IParseable<TQuantity>,
IComparisonOperators<TQuantity, TQuantity>,
IAdditiveIdentity<TQuantity, TQuantity>
where TQuantity : IQuantity<TQuantity>
{
static abstract TQuantity Zero { get; }
}
}
137 changes: 137 additions & 0 deletions ConsoleNet6/Length.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Licensed under MIT No Attribution, see LICENSE file at the root.
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;

namespace ConsoleNet6
{
public enum LengthUnit
{
Meter,
Centimeter
}

[RequiresPreviewFeatures]
public struct Length : IQuantity<Length>
{
public Length(double value, LengthUnit unit)
{
Value = value;
Unit = unit;
}

public double Value { get; }
public LengthUnit Unit { get; }

public static Length AdditiveIdentity => Zero;

public static Length Zero => new Length(0, LengthUnit.Meter);

public static Length Parse(string s, IFormatProvider? provider)
{
if (!TryParse(s, provider, out var length)) throw new ArgumentException(nameof(s));
return length;
}

public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out Length result)
{
if (s == null)
{
result = default;
return false;
}

var m = Regex.Match(s, @"(?<value>[+-]?\d+(?:\.\d+)?) (?<unit>cm|m)");
result = m.Success
? new Length(
double.Parse(m.Groups["value"].Value),
m.Groups["unit"].Value switch {
"m" => LengthUnit.Meter,
"cm" => LengthUnit.Centimeter,
_ => throw new ArgumentException()
})
: default;

return m.Success;
}

public double As(LengthUnit unit)
{
if (unit == Unit) return Value;
if (Unit == LengthUnit.Meter && unit == LengthUnit.Centimeter) return Value * 100;
if (Unit == LengthUnit.Centimeter && unit == LengthUnit.Meter) return Value / 100;
throw new NotImplementedException();
}

public int CompareTo(object? obj)
{
if (obj == null) return 1;
if (obj is not Length other) throw new ArgumentException(nameof(obj));
return CompareTo(other);
}

public int CompareTo(Length other)
{
return Value.CompareTo(other.As(Unit));
}

public bool Equals(Length other)
{
return Value.Equals(other.As(Unit));
}

public static Length operator +(Length left, Length right)
{
return new Length(left.Value + right.As(left.Unit), left.Unit);
}

public static bool operator ==(Length left, Length right)
{
return left.Equals(right);
}

public static bool operator !=(Length left, Length right)
{
return !left.Equals(right);
}

public static bool operator <(Length left, Length right)
{
return left.CompareTo(right) < 0;
}

public static bool operator >(Length left, Length right)
{
return left.CompareTo(right) > 0;
}

public static bool operator <=(Length left, Length right)
{
return left.CompareTo(right) <= 0;
}

public static bool operator >=(Length left, Length right)
{
return left.CompareTo(right) >= 0;
}

public override bool Equals(object? obj)
{
if (obj is not Length other) return false;
return Equals(other);
}

public override int GetHashCode()
{
return new { Value, Unit }.GetHashCode();
}
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "{0} {1}", Value, Unit);
}
}
}
28 changes: 28 additions & 0 deletions ConsoleNet6/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// See https://aka.ms/new-console-template for more information

using ConsoleNet6;
using static System.Console;
using static ConsoleNet6.LengthUnit;

void Foo<TQuantity>(TQuantity left, TQuantity right)
where TQuantity : IQuantity<TQuantity>
{
WriteLine($"Foo({left}, {right})\n---\n");
WriteLine(left.CompareTo(right).ToString().PadRight(20) + "<== left.CompareTo(right)");
WriteLine((left + right).ToString()!.PadRight(20) + "<== left + right");
WriteLine(TQuantity.Parse("25 m", null).ToString()!.PadRight(20) + "<== TQuantity.Parse(\"25 m\", null)");
}

TQuantity Sum<TQuantity>(IEnumerable<TQuantity> items)
where TQuantity : IQuantity<TQuantity>
{
return items.Aggregate(TQuantity.Zero, (acc, item) => acc + item);
}

var oneMeter = new Length(1, Meter);
var tenCentimeters = new Length(10, Centimeter);

Foo(oneMeter, tenCentimeters);

Length[] lengths = new[] { 1, 2, 3, 4 }.Select(val => new Length(val, Meter)).ToArray();
WriteLine(Sum(lengths).ToString()!.PadRight(20) + "<== Sum [1,2,3,4] array of meters");
6 changes: 6 additions & 0 deletions UnitsNet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ ProjectSection(SolutionItems) = preProject
UnitsNet.snk = UnitsNet.snk
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleNet6", "ConsoleNet6\ConsoleNet6.csproj", "{D7B159A9-AA85-406E-BE88-B5B0B6370124}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -86,6 +88,10 @@ Global
{B4996AF5-9A8B-481A-9018-EC7F5B1605FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B4996AF5-9A8B-481A-9018-EC7F5B1605FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B4996AF5-9A8B-481A-9018-EC7F5B1605FF}.Release|Any CPU.Build.0 = Release|Any CPU
{D7B159A9-AA85-406E-BE88-B5B0B6370124}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7B159A9-AA85-406E-BE88-B5B0B6370124}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7B159A9-AA85-406E-BE88-B5B0B6370124}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7B159A9-AA85-406E-BE88-B5B0B6370124}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down