From f3b8d601180a335e2a4544ca30b8b4eccfd81117 Mon Sep 17 00:00:00 2001 From: Vladimir Savkin Date: Wed, 29 Jul 2020 01:42:13 +0600 Subject: [PATCH 1/2] feat: Add CalcResult class Provides the ability to use standard arithmetic operators Replaces the usual approach to throw an exception or return the null in case of an execution failure --- csharp/Platform.Numbers/CalcResult.cs | 461 ++++++++++++++++++++++++++ 1 file changed, 461 insertions(+) create mode 100644 csharp/Platform.Numbers/CalcResult.cs diff --git a/csharp/Platform.Numbers/CalcResult.cs b/csharp/Platform.Numbers/CalcResult.cs new file mode 100644 index 0000000..acc304a --- /dev/null +++ b/csharp/Platform.Numbers/CalcResult.cs @@ -0,0 +1,461 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Platform.Numbers +{ + public class CalcResult + { + public CalcResult() : this(default) { } + + public CalcResult(T value) + { + Value = value; + IsValid = true; + } + + #region Arithmetic operations + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CalcResult Add(T a) + { + if (IsValid) + { + try + { + _value = Arithmetic.Add(_value, a); + } + catch (Exception e) + { + Message = e.Message; + IsValid = false; + } + } + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CalcResult Subtract(T a) + { + if (IsValid) + { + try + { + _value = Arithmetic.Subtract(_value, a); + } + catch (Exception e) + { + Message = e.Message; + IsValid = false; + } + } + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CalcResult Multiply(T a) + { + if (IsValid) + { + try + { + _value = Arithmetic.Multiply(_value, a); + } + catch (Exception e) + { + Message = e.Message; + IsValid = false; + } + } + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CalcResult Divide(T a) + { + if (IsValid) + { + try + { + _value = Arithmetic.Divide(_value, a); + } + catch (Exception e) + { + Message = e.Message; + IsValid = false; + } + } + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CalcResult Add(CalcResult cr) + { + if (IsValid) + { + if (cr.IsValid) + { + try + { + _value = Arithmetic.Add(_value, cr._value); + } + catch (Exception e) + { + Message = e.Message; + IsValid = false; + } + } + else + { + return cr; + } + } + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CalcResult Subtract(CalcResult cr) + { + if (IsValid) + { + if (cr.IsValid) + { + try + { + _value = Arithmetic.Subtract(_value, cr._value); + } + catch (Exception e) + { + Message = e.Message; + IsValid = false; + } + } + else + { + return cr; + } + } + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CalcResult Multiply(CalcResult cr) + { + if (IsValid) + { + if (cr.IsValid) + { + try + { + _value = Arithmetic.Multiply(_value, cr._value); + } + catch (Exception e) + { + Message = e.Message; + IsValid = false; + } + } + else + { + return cr; + } + } + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CalcResult Divide(CalcResult cr) + { + if (IsValid) + { + if (cr.IsValid) + { + try + { + _value = Arithmetic.Divide(_value, cr._value); + } + catch (Exception e) + { + Message = e.Message; + IsValid = false; + } + } + else + { + return cr; + } + } + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CalcResult Increment() + { + if (IsValid) + { + try + { + _value = Arithmetic.Increment(_value); + } + catch (Exception e) + { + Message = e.Message; + IsValid = false; + } + } + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CalcResult Decrement() + { + if (IsValid) + { + try + { + _value = Arithmetic.Decrement(_value); + } + catch (Exception e) + { + Message = e.Message; + IsValid = false; + } + } + return this; + } + #endregion + + public T Value + { + get => _value; + set + { + _value = value; + IsValid = true; + } + } + + public bool IsValid { get; set; } + + public string Message { get; private set; } + + private T _value; + + #region Operator overloading + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CalcResult operator ++(CalcResult cr) + { + if (cr.IsValid) + { + try + { + cr._value = Arithmetic.Increment(cr._value); + } + catch (Exception e) + { + cr.Message = e.Message; + cr.IsValid = false; + } + } + return cr; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CalcResult operator --(CalcResult cr) + { + if (cr.IsValid) + { + try + { + cr._value = Arithmetic.Decrement(cr._value); + } + catch (Exception e) + { + cr.Message = e.Message; + cr.IsValid = false; + } + } + return cr; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CalcResult operator +(CalcResult cr, T v) + { + if (cr.IsValid) + { + try + { + cr._value = Arithmetic.Add(cr._value, v); + } + catch (Exception e) + { + cr.Message = e.Message; + cr.IsValid = false; + } + } + return cr; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CalcResult operator -(CalcResult cr, T v) + { + if (cr.IsValid) + { + try + { + cr._value = Arithmetic.Subtract(cr._value, v); + } + catch (Exception e) + { + cr.Message = e.Message; + cr.IsValid = false; + } + } + return cr; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CalcResult operator *(CalcResult cr, T v) + { + if (cr.IsValid) + { + try + { + cr._value = Arithmetic.Multiply(cr._value, v); + } + catch (Exception e) + { + cr.Message = e.Message; + cr.IsValid = false; + } + } + return cr; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CalcResult operator /(CalcResult cr, T v) + { + if (cr.IsValid) + { + try + { + cr._value = Arithmetic.Divide(cr._value, v); + } + catch (Exception e) + { + cr.Message = e.Message; + cr.IsValid = false; + } + } + return cr; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CalcResult operator +(CalcResult a, CalcResult b) + { + if (a.IsValid) + { + if (b.IsValid) + { + try + { + a._value = Arithmetic.Add(a._value, b._value); + } + catch (Exception e) + { + a.Message = e.Message; + a.IsValid = false; + } + } + else + { + return b; + } + } + return a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CalcResult operator -(CalcResult a, CalcResult b) + { + if (a.IsValid) + { + if (b.IsValid) + { + try + { + a._value = Arithmetic.Subtract(a._value, b._value); + } + catch (Exception e) + { + a.Message = e.Message; + a.IsValid = false; + } + } + else + { + return b; + } + } + return a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CalcResult operator *(CalcResult a, CalcResult b) + { + if (a.IsValid) + { + if (b.IsValid) + { + try + { + a._value = Arithmetic.Multiply(a._value, b._value); + } + catch (Exception e) + { + a.Message = e.Message; + b.IsValid = false; + } + } + else + { + return b; + } + } + return a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CalcResult operator /(CalcResult a, CalcResult b) + { + if (a.IsValid) + { + if (b.IsValid) + { + try + { + a._value = Arithmetic.Divide(a._value, b._value); + } + catch (Exception e) + { + a.Message = e.Message; + a.IsValid = false; + } + } + else + { + return b; + } + } + return a; + } + + #endregion + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator bool(CalcResult v) => v.IsValid; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator CalcResult(T v) => new CalcResult(v); + } +} From c5219ff86e161846621cc5ee9dd03e6051b1aad9 Mon Sep 17 00:00:00 2001 From: Vladimir Savkin Date: Wed, 29 Jul 2020 01:43:29 +0600 Subject: [PATCH 2/2] feat: Add CalcResultTests Add simple integration test Add tests on arithmetic operations and use operators --- .../Platform.Numbers.Tests/CalcResultTests.cs | 193 ++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 csharp/Platform.Numbers.Tests/CalcResultTests.cs diff --git a/csharp/Platform.Numbers.Tests/CalcResultTests.cs b/csharp/Platform.Numbers.Tests/CalcResultTests.cs new file mode 100644 index 0000000..a2fa0bb --- /dev/null +++ b/csharp/Platform.Numbers.Tests/CalcResultTests.cs @@ -0,0 +1,193 @@ +using System.Collections.Generic; +using Xunit; + +namespace Platform.Numbers.Tests +{ + public static class CalcResultTests + { + [Fact] + public static void SimpleIntegration_Test() + { + //arrange + int expected = (5 + 6) * (3 + (9 / 3)); + expected++; + expected++; + expected--; + + //act + var result = ((CalcResult)5 + 6) * (3 + (9 / (CalcResult)3)); + result.Increment(); + result++; + result--; + + //assert + Assert.Equal(expected, result.Value); + } + + [Theory] + [MemberData(nameof(Data))] + public static void ArithmeticOperation_Test(ArithmeticOpetation op, int a, int b) + { + //arrange + int expected = a; + var result = new CalcResult(a); + + //act + if (op == ArithmeticOpetation.Add) + { + result.Add(b); + expected += b; + } + + if (op == ArithmeticOpetation.Subtract) + { + result.Subtract(b); + expected -= b; + } + + if (op == ArithmeticOpetation.Multiply) + { + result.Multiply(b); + expected *= b; + } + + if (op == ArithmeticOpetation.Divide) + { + result.Divide(b); + expected /= b; + } + + //assert + Assert.Equal(expected, result.Value); + } + + [Theory] + [MemberData(nameof(Data))] + public static void ArithmeticOperation_Test2(ArithmeticOpetation op, int a, int b) + { + //arrange + int expected = a; + var result = new CalcResult(a); + var _b = new CalcResult(b); + //act + if (op == ArithmeticOpetation.Add) + { + result.Add(_b); + expected += b; + } + + if (op == ArithmeticOpetation.Subtract) + { + result.Subtract(_b); + expected -= b; + } + + if (op == ArithmeticOpetation.Multiply) + { + result.Multiply(_b); + expected *= b; + } + + if (op == ArithmeticOpetation.Divide) + { + result.Divide(_b); + expected /= b; + } + + //assert + Assert.Equal(expected, result.Value); + } + public static IEnumerable Data() + { + yield return new object[] {ArithmeticOpetation.Add, 40, 2}; + + yield return new object[] { ArithmeticOpetation.Subtract, 44, 2}; + + yield return new object[] { ArithmeticOpetation.Multiply, 21, 2 }; + + yield return new object[] { ArithmeticOpetation.Divide, 84, 2 }; + } + + [Theory] + [MemberData(nameof(Data))] + public static void Operators_Test(ArithmeticOpetation op, int a, int b) + { + //arrange + int expected = a; + var result = new CalcResult(a); + //act + if (op == ArithmeticOpetation.Add) + { + result += b; + expected += b; + } + + if (op == ArithmeticOpetation.Subtract) + { + result -= b; + expected -= b; + } + + if (op == ArithmeticOpetation.Multiply) + { + result *= b; + expected *= b; + } + + if (op == ArithmeticOpetation.Divide) + { + result /= b; + expected /= b; + } + + //assert + Assert.Equal(expected, result.Value); + } + + [Theory] + [MemberData(nameof(Data))] + public static void Operators_Test2(ArithmeticOpetation op, int a, int b) + { + //arrange + int expected = a; + var result = new CalcResult(a); + var _b = new CalcResult(b); + + //act + if (op == ArithmeticOpetation.Add) + { + result += _b; + expected += b; + } + + if (op == ArithmeticOpetation.Subtract) + { + result -= _b; + expected -= b; + } + + if (op == ArithmeticOpetation.Multiply) + { + result *= _b; + expected *= b; + } + + if (op == ArithmeticOpetation.Divide) + { + result /= _b; + expected /= b; + } + + //assert + Assert.Equal(expected, result.Value); + } + + public enum ArithmeticOpetation + { + Add, + Subtract, + Multiply, + Divide + } + } +}