From ceaa104a1f9d434c5e7c7f59b58d94043dcff50a Mon Sep 17 00:00:00 2001 From: Prophet Lamb Date: Tue, 28 Jun 2022 14:58:12 +0200 Subject: [PATCH 1/7] Fix leaky target constraint --- CSharpFunctionalExtensions/CSharpFunctionalExtensions.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CSharpFunctionalExtensions/CSharpFunctionalExtensions.csproj b/CSharpFunctionalExtensions/CSharpFunctionalExtensions.csproj index 1096c335..6d4c84a3 100644 --- a/CSharpFunctionalExtensions/CSharpFunctionalExtensions.csproj +++ b/CSharpFunctionalExtensions/CSharpFunctionalExtensions.csproj @@ -45,7 +45,7 @@ - + all @@ -53,7 +53,7 @@ - + From 8f90ee82cf5d65bfa918874acf36ef7a51d30446 Mon Sep 17 00:00:00 2001 From: Prophet Lamb Date: Tue, 28 Jun 2022 15:00:15 +0200 Subject: [PATCH 2/7] Inline payload retrieval --- CSharpFunctionalExtensions/Maybe/Maybe.cs | 25 ++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/CSharpFunctionalExtensions/Maybe/Maybe.cs b/CSharpFunctionalExtensions/Maybe/Maybe.cs index 23f0b7f7..fe8c2b5f 100644 --- a/CSharpFunctionalExtensions/Maybe/Maybe.cs +++ b/CSharpFunctionalExtensions/Maybe/Maybe.cs @@ -1,4 +1,10 @@ using System; +#if NETCORE || NETSTANDARD || NET45_OR_GREATER +using System.Runtime.CompilerServices; +#endif +#if NET_5_0_OR_GREATER +using System.Diagnostics.CodeAnalysis; +#endif namespace CSharpFunctionalExtensions { @@ -28,6 +34,23 @@ public T GetValueOrDefault(T defaultValue = default) return _value; } + + /// + /// Indicates whether the inner value is present and returns the value if it is. + /// + /// The inner value, if present; otherwise `default` +#if NETCORE || NETSTANDARD || NET45_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryGetValue( +#if NET_5_0_OR_GREATER + [NotNullWhen(true), MaybeNullWhen(false)] +#endif + out T value) + { + value = _value; + return _isValueSet; + } /// /// Try to use GetValueOrThrow() or GetValueOrDefault() instead for better explicitness. @@ -159,7 +182,7 @@ public struct Maybe /// /// Useful in scenarios where you need to determine if a value is Maybe or not /// - public interface IMaybe + public interface IMaybe { T Value { get; } bool HasValue { get; } From 052dd031f41d2385506a403f5250ba19f13563cd Mon Sep 17 00:00:00 2001 From: Prophet Lamb Date: Tue, 28 Jun 2022 15:05:11 +0200 Subject: [PATCH 3/7] Unit tests for inline payload retrieval --- .../MaybeTests/BasicTests.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CSharpFunctionalExtensions.Tests/MaybeTests/BasicTests.cs b/CSharpFunctionalExtensions.Tests/MaybeTests/BasicTests.cs index ae6c7a21..f2b925da 100644 --- a/CSharpFunctionalExtensions.Tests/MaybeTests/BasicTests.cs +++ b/CSharpFunctionalExtensions.Tests/MaybeTests/BasicTests.cs @@ -172,6 +172,46 @@ public void Maybe_None_doesnt_throw_on_Deconstruct() act.Should().NotThrow(); } + + public void TryGetValue_returns_false_if_source_is_empty() + { + var maybe = Maybe.None; + + bool result = maybe.TryGetValue(out int value); + + result.Should().BeFalse(); + value.Should().Be(default); + } + + public void TryGetValue_returns_true_if_source_has_value() + { + var maybe = Maybe.From(5); + + bool result = maybe.TryGetValue(out int value); + + result.Should().BeTrue(); + value.Should().Be(5); + } + + public void TryGetValue_returns_false_if_source_is_empty_and_out_parameter_is_null() + { + var maybe = Maybe.None; + + bool result = maybe.TryGetValue(out int? value); + + result.Should().BeFalse(); + value.Should().BeNull(); + } + + public void TryGetValue_returns_true_if_source_has_value_and_out_parameter_is_null() + { + var maybe = Maybe.From(5); + + bool result = maybe.TryGetValue(out int? value); + + result.Should().BeTrue(); + value.Should().Be(5); + } private class MyClass { From aa53c55de1107df2c0f425f7fa555dccb292ba74 Mon Sep 17 00:00:00 2001 From: Prophet Lamb Date: Tue, 28 Jun 2022 17:24:31 +0200 Subject: [PATCH 4/7] Declare tests as such --- CSharpFunctionalExtensions.Tests/MaybeTests/BasicTests.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CSharpFunctionalExtensions.Tests/MaybeTests/BasicTests.cs b/CSharpFunctionalExtensions.Tests/MaybeTests/BasicTests.cs index f2b925da..b92a1401 100644 --- a/CSharpFunctionalExtensions.Tests/MaybeTests/BasicTests.cs +++ b/CSharpFunctionalExtensions.Tests/MaybeTests/BasicTests.cs @@ -161,6 +161,7 @@ public void GetValueOrThrow_returns_value_if_source_has_value() result.Should().Be(value); } + [Fact] public void Maybe_None_doesnt_throw_on_Deconstruct() { Maybe maybe = Maybe.None; @@ -173,6 +174,7 @@ public void Maybe_None_doesnt_throw_on_Deconstruct() act.Should().NotThrow(); } + [Fact] public void TryGetValue_returns_false_if_source_is_empty() { var maybe = Maybe.None; @@ -183,6 +185,7 @@ public void TryGetValue_returns_false_if_source_is_empty() value.Should().Be(default); } + [Fact] public void TryGetValue_returns_true_if_source_has_value() { var maybe = Maybe.From(5); @@ -193,6 +196,7 @@ public void TryGetValue_returns_true_if_source_has_value() value.Should().Be(5); } + [Fact] public void TryGetValue_returns_false_if_source_is_empty_and_out_parameter_is_null() { var maybe = Maybe.None; @@ -203,6 +207,7 @@ public void TryGetValue_returns_false_if_source_is_empty_and_out_parameter_is_nu value.Should().BeNull(); } + [Fact] public void TryGetValue_returns_true_if_source_has_value_and_out_parameter_is_null() { var maybe = Maybe.From(5); From bc97fb56053bc04d884adb3d8c18f5c30b627656 Mon Sep 17 00:00:00 2001 From: Prophet Lamb Date: Wed, 6 Jul 2022 15:08:17 +0200 Subject: [PATCH 5/7] Implement `TryGetSuccess` & `TryGetFailure` endofunctors --- .../Result/Methods/TryGet.cs | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 CSharpFunctionalExtensions/Result/Methods/TryGet.cs diff --git a/CSharpFunctionalExtensions/Result/Methods/TryGet.cs b/CSharpFunctionalExtensions/Result/Methods/TryGet.cs new file mode 100644 index 00000000..29365b93 --- /dev/null +++ b/CSharpFunctionalExtensions/Result/Methods/TryGet.cs @@ -0,0 +1,176 @@ +#if NETCORE || NETSTANDARD || NET45_OR_GREATER +using System.Runtime.CompilerServices; +#endif +#if NET_5_0_OR_GREATER +using System.Diagnostics.CodeAnalysis; +#endif + +namespace CSharpFunctionalExtensions +{ + partial struct Result + { +#if NETCORE || NETSTANDARD || NET45_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryGetFailure( +#if NET_5_0_OR_GREATER + [NotNullWhen(true), MaybeNullWhen(false)] +#endif + out string error) + { + error = _error; + return IsFailure; + } + } + + partial struct Result + { +#if NETCORE || NETSTANDARD || NET45_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryGetSuccess( +#if NET_5_0_OR_GREATER + [NotNullWhen(true), MaybeNullWhen(false)] +#endif + out T value) + { + value = _value; + return IsSuccess; + } + +#if NETCORE || NETSTANDARD || NET45_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryGetFailure( +#if NET_5_0_OR_GREATER + [NotNullWhen(true), MaybeNullWhen(false)] +#endif + out string error) + { + error = _error; + return IsFailure; + } + +#if NETCORE || NETSTANDARD || NET45_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryGetSuccess( +#if NET_5_0_OR_GREATER + [NotNullWhen(true), MaybeNullWhen(false)] +#endif + out T value, +#if NET_5_0_OR_GREATER + [NotNullWhen(false), MaybeNullWhen(true)] +#endif + out string error + ) + { + value = _value; + error = _error; + return IsSuccess; + } + +#if NETCORE || NETSTANDARD || NET45_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryGetFailure( +#if NET_5_0_OR_GREATER + [NotNullWhen(true), MaybeNullWhen(false)] +#endif + out string error, +#if NET_5_0_OR_GREATER + [NotNullWhen(false), MaybeNullWhen(true)] +#endif + out T value + ) + { + value = _value; + error = _error; + return IsFailure; + } + } + + partial struct Result + { + +#if NETCORE || NETSTANDARD || NET45_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryGetSuccess( +#if NET_5_0_OR_GREATER + [NotNullWhen(true), MaybeNullWhen(false)] +#endif + out T value) + { + value = _value; + return IsSuccess; + } + +#if NETCORE || NETSTANDARD || NET45_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryGetFailure( +#if NET_5_0_OR_GREATER + [NotNullWhen(true), MaybeNullWhen(false)] +#endif + out E error) + { + error = _error; + return IsFailure; + } + +#if NETCORE || NETSTANDARD || NET45_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryGetSuccess( +#if NET_5_0_OR_GREATER + [NotNullWhen(true), MaybeNullWhen(false)] +#endif + out T value, +#if NET_5_0_OR_GREATER + [NotNullWhen(false), MaybeNullWhen(true)] +#endif + out E error + ) + { + value = _value; + error = _error; + return IsSuccess; + } + +#if NETCORE || NETSTANDARD || NET45_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryGetFailure( +#if NET_5_0_OR_GREATER + [NotNullWhen(true), MaybeNullWhen(false)] +#endif + out E error, +#if NET_5_0_OR_GREATER + [NotNullWhen(false), MaybeNullWhen(true)] +#endif + out T value + ) + { + value = _value; + error = _error; + return IsFailure; + } + } + + partial struct UnitResult + { +#if NETCORE || NETSTANDARD || NET45_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryGetFailure( +#if NET_5_0_OR_GREATER + [NotNullWhen(true), MaybeNullWhen(false)] +#endif + out E error) + { + error = _error; + return IsFailure; + } + } +} \ No newline at end of file From 2ba31087d11f71e0a12a020ea4f8fe9ad45c3970 Mon Sep 17 00:00:00 2001 From: ProphetLamb Date: Wed, 6 Jul 2022 23:03:26 +0200 Subject: [PATCH 6/7] Rename `TryGetValue` & `TryGetError` --- .../Result/Methods/TryGet.cs | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/CSharpFunctionalExtensions/Result/Methods/TryGet.cs b/CSharpFunctionalExtensions/Result/Methods/TryGet.cs index 29365b93..a689078b 100644 --- a/CSharpFunctionalExtensions/Result/Methods/TryGet.cs +++ b/CSharpFunctionalExtensions/Result/Methods/TryGet.cs @@ -11,8 +11,8 @@ partial struct Result { #if NETCORE || NETSTANDARD || NET45_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryGetFailure( +#endif + public bool TryGetError( #if NET_5_0_OR_GREATER [NotNullWhen(true), MaybeNullWhen(false)] #endif @@ -27,8 +27,8 @@ partial struct Result { #if NETCORE || NETSTANDARD || NET45_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryGetSuccess( +#endif + public bool TryGetValue( #if NET_5_0_OR_GREATER [NotNullWhen(true), MaybeNullWhen(false)] #endif @@ -37,11 +37,11 @@ public bool TryGetSuccess( value = _value; return IsSuccess; } - + #if NETCORE || NETSTANDARD || NET45_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryGetFailure( +#endif + public bool TryGetError( #if NET_5_0_OR_GREATER [NotNullWhen(true), MaybeNullWhen(false)] #endif @@ -50,11 +50,11 @@ public bool TryGetFailure( error = _error; return IsFailure; } - + #if NETCORE || NETSTANDARD || NET45_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public bool TryGetSuccess( + public bool TryGetValue( #if NET_5_0_OR_GREATER [NotNullWhen(true), MaybeNullWhen(false)] #endif @@ -73,7 +73,7 @@ out string error #if NETCORE || NETSTANDARD || NET45_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public bool TryGetFailure( + public bool TryGetError( #if NET_5_0_OR_GREATER [NotNullWhen(true), MaybeNullWhen(false)] #endif @@ -89,14 +89,14 @@ out T value return IsFailure; } } - + partial struct Result { - + #if NETCORE || NETSTANDARD || NET45_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryGetSuccess( +#endif + public bool TryGetValue( #if NET_5_0_OR_GREATER [NotNullWhen(true), MaybeNullWhen(false)] #endif @@ -105,11 +105,11 @@ public bool TryGetSuccess( value = _value; return IsSuccess; } - + #if NETCORE || NETSTANDARD || NET45_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryGetFailure( +#endif + public bool TryGetError( #if NET_5_0_OR_GREATER [NotNullWhen(true), MaybeNullWhen(false)] #endif @@ -122,7 +122,7 @@ public bool TryGetFailure( #if NETCORE || NETSTANDARD || NET45_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public bool TryGetSuccess( + public bool TryGetValue( #if NET_5_0_OR_GREATER [NotNullWhen(true), MaybeNullWhen(false)] #endif @@ -141,7 +141,7 @@ out E error #if NETCORE || NETSTANDARD || NET45_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public bool TryGetFailure( + public bool TryGetError( #if NET_5_0_OR_GREATER [NotNullWhen(true), MaybeNullWhen(false)] #endif @@ -162,8 +162,8 @@ partial struct UnitResult { #if NETCORE || NETSTANDARD || NET45_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryGetFailure( +#endif + public bool TryGetError( #if NET_5_0_OR_GREATER [NotNullWhen(true), MaybeNullWhen(false)] #endif From aa959c25fb51027c8d734b7cb9fe7c9389b02512 Mon Sep 17 00:00:00 2001 From: ProphetLamb Date: Wed, 6 Jul 2022 23:04:06 +0200 Subject: [PATCH 7/7] Testcases for Result// --- .../ResultTests/Methods/TryGetTests.cs | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 CSharpFunctionalExtensions.Tests/ResultTests/Methods/TryGetTests.cs diff --git a/CSharpFunctionalExtensions.Tests/ResultTests/Methods/TryGetTests.cs b/CSharpFunctionalExtensions.Tests/ResultTests/Methods/TryGetTests.cs new file mode 100644 index 00000000..d3df2e9c --- /dev/null +++ b/CSharpFunctionalExtensions.Tests/ResultTests/Methods/TryGetTests.cs @@ -0,0 +1,92 @@ +using System; + +using FluentAssertions; +using Xunit; + +namespace CSharpFunctionalExtensions.Tests.ResultTests.Methods +{ + public class TryGetTests + { + public const string ErrorMessage = "Error from result"; + + [Fact] + public void Simple_result_tryGetError_is_false_Success_value_expected() + { + Result result = Result.Success(ErrorMessage); + result.TryGetError(out string error).Should().BeFalse(); + error.Should().BeNull(); + } + + [Fact] + public void Simple_result_tryGetError_is_true_Failure_value_expected() + { + Result result = Result.Failure(ErrorMessage); + result.TryGetError(out string error).Should().BeTrue(); + error.Should().Be(ErrorMessage); + } + + [Fact] + public void Generic_result_tryGetError_is_false_Success_value_expected() + { + Result result = Result.Success("Success"); + result.TryGetError(out string error).Should().BeFalse(); + error.Should().BeNull(); + } + + [Fact] + public void Generic_result_tryGetError_is_true_Failure_value_expected() + { + Result result = Result.Failure(ErrorMessage); + result.TryGetError(out string error).Should().BeTrue(); + error.Should().Be(ErrorMessage); + } + + [Fact] + public void Generic_result_tryGetSuccess_is_false_Failure_value_expected() + { + Result result = Result.Failure(ErrorMessage); + result.TryGetValue(out string value).Should().BeFalse(); + value.Should().BeNull(); + } + + [Fact] + public void Generic_result_tryGetSuccess_is_true_Success_value_expected() + { + Result result = Result.Success("Success"); + result.TryGetValue(out string value).Should().BeTrue(); + value.Should().Be("Success"); + } + + [Fact] + public void Value_Error_Generic_result_tryGetError_is_false_Success_value_expected() + { + Result result = Result.Success("Success"); + result.TryGetError(out string error).Should().BeFalse(); + error.Should().BeNull(); + } + + [Fact] + public void Value_Error_Generic_result_tryGetError_is_true_Failure_value_expected() + { + Result result = Result.Failure(ErrorMessage); + result.TryGetError(out string error).Should().BeTrue(); + error.Should().Be(ErrorMessage); + } + + [Fact] + public void Value_Error_Generic_result_tryGetSuccess_is_false_Failure_value_expected() + { + Result result = Result.Failure(ErrorMessage); + result.TryGetValue(out string value).Should().BeFalse(); + value.Should().BeNull(); + } + + [Fact] + public void Value_Error_Generic_result_tryGetSuccess_is_true_Success_value_expected() + { + Result result = Result.Success("Success"); + result.TryGetValue(out string value).Should().BeTrue(); + value.Should().Be("Success"); + } + } +} \ No newline at end of file