diff --git a/ConsoleNet6/ConsoleNet6.csproj b/ConsoleNet6/ConsoleNet6.csproj new file mode 100644 index 0000000000..67b8794ed2 --- /dev/null +++ b/ConsoleNet6/ConsoleNet6.csproj @@ -0,0 +1,16 @@ + + + + Exe + net6.0 + preview + enable + enable + + + + + + + + diff --git a/ConsoleNet6/IQuantity.cs b/ConsoleNet6/IQuantity.cs new file mode 100644 index 0000000000..1a982775db --- /dev/null +++ b/ConsoleNet6/IQuantity.cs @@ -0,0 +1,15 @@ +// 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 ConsoleNet6 +{ + public interface IQuantity : + IAdditionOperators, + IParseable, + IComparisonOperators, + IAdditiveIdentity + where TQuantity : IQuantity + { + static abstract TQuantity Zero { get; } + } +} diff --git a/ConsoleNet6/Length.cs b/ConsoleNet6/Length.cs new file mode 100644 index 0000000000..4f5f433d79 --- /dev/null +++ b/ConsoleNet6/Length.cs @@ -0,0 +1,137 @@ +// 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. + +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 + { + 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, @"(?[+-]?\d+(?:\.\d+)?) (?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); + } + } +} diff --git a/ConsoleNet6/Program.cs b/ConsoleNet6/Program.cs new file mode 100644 index 0000000000..05658e4cca --- /dev/null +++ b/ConsoleNet6/Program.cs @@ -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 left, TQuantity right) + where TQuantity : IQuantity +{ + 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(IEnumerable items) + where TQuantity : IQuantity +{ + 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"); diff --git a/UnitsNet.sln b/UnitsNet.sln index 4e089aca8d..af16d67e5b 100644 --- a/UnitsNet.sln +++ b/UnitsNet.sln @@ -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 @@ -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