From 993a8295ee50e5decfdfd86b6c21fef54a86586b Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 9 Mar 2020 21:49:39 +0100 Subject: [PATCH 01/10] Added Guard APIs docs --- docs/developer-tools/Guard.md | 104 ++++++++++++++++++++++++++++++++++ docs/toc.md | 1 + 2 files changed, 105 insertions(+) create mode 100644 docs/developer-tools/Guard.md diff --git a/docs/developer-tools/Guard.md b/docs/developer-tools/Guard.md new file mode 100644 index 000000000..ffec84ccd --- /dev/null +++ b/docs/developer-tools/Guard.md @@ -0,0 +1,104 @@ +--- +title: Guard +author: Sergio0694 +description: Helper methods to verify conditions when running code +keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, debug, net core, net standard +dev_langs: + - csharp +--- + +# Guard + +The [Guard](https://docs.microsoft.com/dotnet/api/microsoft.toolkit.diagnostics.guard) can be used to validate method arguments in a streamlined manner, which is also faster, less verbose, more expressive and less error prone than manually writing checks and throwing exceptions. + +## How it works + +These `Guard` APIs are built with three core principles in mind: + +- Being **fast**. To achieve that, all the APIs have been designed to produce as little code as possible in the caller, and each single Guard API will (almost always) be inlined. Furthermore, specialized methods are generated with T4 templates to achieve the most efficient assembly code possible when working with common types (eg. primitive numeric types). +- Being **helpful**. Each `Guard` API produces a detailed exception message that clearly specifies what went wrong, along with additional info (eg. current variable values), when applicable. +- Being **intuitive**. To achieve this, all the `Guard` APIs have expressive and self-explanatory names that make it immediately clear what each API is supposed to do. This shifts the burden of writing checks away from the developers, letting them express conditions using natural language. + +## Syntax + +Here is a sample method, with some checks being done with explicit checks and manual throw statements: + +```csharp +public static void SampleMethod(int[] array, int index, Span span, string text) +{ + if (array is null) + { + throw new ArgumentNullException(nameof(array), "The array must not be null"); + } + + if (array.Length >= 10) + { + throw new ArgumentException($"The array must have less than 10 items, had a size of {array.Length}", nameof(array)); + } + + if (index < 0 || index >= array.Length) + { + throw new ArgumentOutOfRangeException(nameof(index), $"The index must be in the [0, {array.Length}) range, was {index}"); + } + + if (span.Length < array.Length) + { + throw new ArgumentException($"The target span is shorter than the input array, had a length of {span.Length}", nameof(span)); + } + + if (string.IsNullOrEmpty(text)) + { + throw new ArgumentException("The input text can't be null or empty", nameof(text)); + } +} +``` + +And here is the same method, but using the new `Guard.APIs` to validate the input arguments: + +```csharp +public static void SampleMethod(int[] array, int index, Span span, string text) +{ + Guard.IsNotNull(array, nameof(array)); + Guard.HasSizeAtLeast(array, 10, nameof(array)); + Guard.IsInRangeFor(index, array, nameof(index)); + Guard.HasSizeLessThanOrEqualTo(array, span, nameof(span)); + Guard.IsNotNullOrEmpty(text, nameof(text)); +} +``` + +The `Guard` APIs will perform the required checks in the fastest way possible, and will throw the appropriate exception with a well formated message if they fail. + +## Methods + +There are dozens of different APIs and overloads in the `Guard` class, here are a few of them: + +| Methods | Return Type | Description | +| -- | -- | -- | +| IsNotNull(T?, string) | void | Asserts that the input value is not null | +| IsOfType(object, string) | void | Asserts that the input value is of a specific type | +| IsReferenceEqualTo(T, T, string) | void | Asserts that the input value must be the same instance as the target value | +| IsTrue(bool, string) | void | Asserts that the input value must be true | +| IsEqualTo(T, T, string) | void | Asserts that the input value must be equal to a specified value | +| IsLessThan(T, T, string) | void | Asserts that the input value must be less than a specified value | +| IsLessThanOrEqualTo(T, T, string) | void | Asserts that the input value must be less than or equal to a specified value | +| IsInRange(T, T, T, string) | void | Asserts that the input value must be in a given range | +| IsInRangeFor(int, T[], string) | void | Asserts that the input index is valid for a given array | +| IsNotEmpty(T[], string) | void | Asserts that the input array must not be empty | +| HasSizeEqualTo(T[], int, string) | void | Asserts that the input array must have a size of a specified value | +| IsCompleted(Task, string) | void | Asserts that the input task is in a completed state | +| IsNotCanceled(Task, string) | void | Asserts that the input task is not canceled | + +## Sample Code + +You can find more examples in our [unit tests](https://github.com/Microsoft/WindowsCommunityToolkit//blob/master/UnitTests/Diagnostics/Test_Guard.cs) + +## Requirements + +| Device family | Universal, 10.0.16299.0 or higher | +| --- | --- | +| Namespace | Microsoft.Toolkit.Diagnostics | +| NuGet package | [Microsoft.Toolkit](https://www.nuget.org/packages/Microsoft.Toolkit/) | + +## API + +* [Guard source code](https://github.com/Microsoft/WindowsCommunityToolkit//blob/master/Microsoft.Toolkit/Diagnostics) diff --git a/docs/toc.md b/docs/toc.md index 1c9c0cf54..0877724b8 100644 --- a/docs/toc.md +++ b/docs/toc.md @@ -167,6 +167,7 @@ # Developer tools ## [AlignmentGrid](developer-tools/AlignmentGrid.md) ## [FocusTracker](developer-tools/FocusTracker.md) +## [Guard](developer-tools/Guard.md) # [GazeInteractionLibrary](gaze/GazeInteractionLibrary.md) From 3e9f73f7032c66bec5f1efea683d366b57088046 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 11 Mar 2020 00:25:39 +0100 Subject: [PATCH 02/10] Added details for APIs used in the sample --- docs/developer-tools/Guard.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/developer-tools/Guard.md b/docs/developer-tools/Guard.md index ffec84ccd..297379c2f 100644 --- a/docs/developer-tools/Guard.md +++ b/docs/developer-tools/Guard.md @@ -75,6 +75,10 @@ There are dozens of different APIs and overloads in the `Guard` class, here are | Methods | Return Type | Description | | -- | -- | -- | | IsNotNull(T?, string) | void | Asserts that the input value is not null | +| HasSizeAtLeast(T[], int, string) | void | Asserts that the input array must have a size of at least or equal to a specified value | +| IsInRangeFor(int, T[], string) | void | Asserts that the input index is valid for a given array | +| HasSizeLessThanOrEqualTo(T[], T[], string) | void | Asserts that the source array must have a size of less than or equal to that of the destination array | +| IsNotNullOrEmpty(string, string) | void | Asserts that the input string instance must not be null or empty | | IsOfType(object, string) | void | Asserts that the input value is of a specific type | | IsReferenceEqualTo(T, T, string) | void | Asserts that the input value must be the same instance as the target value | | IsTrue(bool, string) | void | Asserts that the input value must be true | From 78e2da312b3d4cf698f2b49475cb03ea11501d3b Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 11 Mar 2020 00:27:38 +0100 Subject: [PATCH 03/10] Added .NET Standard mention --- docs/developer-tools/Guard.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/developer-tools/Guard.md b/docs/developer-tools/Guard.md index 297379c2f..79c74977b 100644 --- a/docs/developer-tools/Guard.md +++ b/docs/developer-tools/Guard.md @@ -103,6 +103,8 @@ You can find more examples in our [unit tests](https://github.com/Microsoft/Wind | Namespace | Microsoft.Toolkit.Diagnostics | | NuGet package | [Microsoft.Toolkit](https://www.nuget.org/packages/Microsoft.Toolkit/) | +The Array Extensions supports .NET Standard + ## API * [Guard source code](https://github.com/Microsoft/WindowsCommunityToolkit//blob/master/Microsoft.Toolkit/Diagnostics) From 7384d3ea024fd3c9abd6223fc4bbab5eac279b3e Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 11 Mar 2020 00:31:16 +0100 Subject: [PATCH 04/10] Fixed a copy-paste fail --- docs/developer-tools/Guard.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer-tools/Guard.md b/docs/developer-tools/Guard.md index 79c74977b..50a799fa3 100644 --- a/docs/developer-tools/Guard.md +++ b/docs/developer-tools/Guard.md @@ -103,7 +103,7 @@ You can find more examples in our [unit tests](https://github.com/Microsoft/Wind | Namespace | Microsoft.Toolkit.Diagnostics | | NuGet package | [Microsoft.Toolkit](https://www.nuget.org/packages/Microsoft.Toolkit/) | -The Array Extensions supports .NET Standard +The Guard class supports .NET Standard ## API From aac780b39ea650bfcb0208f3581bd19f2627ce6c Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 11 Mar 2020 00:50:34 +0100 Subject: [PATCH 05/10] Grouped APIs by category --- docs/developer-tools/Guard.md | 39 ++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/docs/developer-tools/Guard.md b/docs/developer-tools/Guard.md index 50a799fa3..91434d2ce 100644 --- a/docs/developer-tools/Guard.md +++ b/docs/developer-tools/Guard.md @@ -72,23 +72,48 @@ The `Guard` APIs will perform the required checks in the fastest way possible, a There are dozens of different APIs and overloads in the `Guard` class, here are a few of them: +### General + | Methods | Return Type | Description | | -- | -- | -- | -| IsNotNull(T?, string) | void | Asserts that the input value is not null | -| HasSizeAtLeast(T[], int, string) | void | Asserts that the input array must have a size of at least or equal to a specified value | -| IsInRangeFor(int, T[], string) | void | Asserts that the input index is valid for a given array | -| HasSizeLessThanOrEqualTo(T[], T[], string) | void | Asserts that the source array must have a size of less than or equal to that of the destination array | -| IsNotNullOrEmpty(string, string) | void | Asserts that the input string instance must not be null or empty | +| IsNotNull(T, string) | void | Asserts that the input value is not null | | IsOfType(object, string) | void | Asserts that the input value is of a specific type | +| IsAssignableToType(object, string) | void | Asserts that the input value can be assigned to a specified type | | IsReferenceEqualTo(T, T, string) | void | Asserts that the input value must be the same instance as the target value | | IsTrue(bool, string) | void | Asserts that the input value must be true | + +### Comparisons + +| Methods | Return Type | Description | +| -- | -- | -- | | IsEqualTo(T, T, string) | void | Asserts that the input value must be equal to a specified value | +| IsBitwiseEqualTo(T, T, string) | void | Asserts that the input value must be a bitwise match with a specified value | | IsLessThan(T, T, string) | void | Asserts that the input value must be less than a specified value | | IsLessThanOrEqualTo(T, T, string) | void | Asserts that the input value must be less than or equal to a specified value | | IsInRange(T, T, T, string) | void | Asserts that the input value must be in a given range | +| IsBetween(T, T, T, string name) | void | Asserts that the input value must be in a given interval | + +### Strings + +| Methods | Return Type | Description | +| -- | -- | -- | +| IsNotNullOrEmpty(string, string) | void | Asserts that the input string instance must not be null or empty | +| IsNotNullOrWhitespace(string, string) | void | Asserts that the input string instance must not be null or whitespace | + +### Collections + +| Methods | Return Type | Description | +| -- | -- | -- | +| IsNotEmpty(T[], string) | void | Asserts that the input array instance must not be empty | +| HasSizeEqualTo(T[], int, string) | void | Asserts that the input array instance must have a size of a specified value | +| HasSizeAtLeast(T[], int, string) | void | Asserts that the input array must have a size of at least or equal to a specified value | | IsInRangeFor(int, T[], string) | void | Asserts that the input index is valid for a given array | -| IsNotEmpty(T[], string) | void | Asserts that the input array must not be empty | -| HasSizeEqualTo(T[], int, string) | void | Asserts that the input array must have a size of a specified value | +| HasSizeLessThanOrEqualTo(T[], T[], string) | void | Asserts that the source array must have a size of less than or equal to that of the destination array | + +### Tasks + +| Methods | Return Type | Description | +| -- | -- | -- | | IsCompleted(Task, string) | void | Asserts that the input task is in a completed state | | IsNotCanceled(Task, string) | void | Asserts that the input task is not canceled | From 3a1849e14914b7930af54edc99198d9263342178 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 11 Mar 2020 00:51:18 +0100 Subject: [PATCH 06/10] Fixed display in markdown --- docs/developer-tools/Guard.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/developer-tools/Guard.md b/docs/developer-tools/Guard.md index 91434d2ce..86268bb28 100644 --- a/docs/developer-tools/Guard.md +++ b/docs/developer-tools/Guard.md @@ -76,22 +76,22 @@ There are dozens of different APIs and overloads in the `Guard` class, here are | Methods | Return Type | Description | | -- | -- | -- | -| IsNotNull(T, string) | void | Asserts that the input value is not null | -| IsOfType(object, string) | void | Asserts that the input value is of a specific type | -| IsAssignableToType(object, string) | void | Asserts that the input value can be assigned to a specified type | -| IsReferenceEqualTo(T, T, string) | void | Asserts that the input value must be the same instance as the target value | +| IsNotNull<T>(T, string) | void | Asserts that the input value is not null | +| IsOfType<T>(object, string) | void | Asserts that the input value is of a specific type | +| IsAssignableToType<T>(object, string) | void | Asserts that the input value can be assigned to a specified type | +| IsReferenceEqualTo<T>(T, T, string) | void | Asserts that the input value must be the same instance as the target value | | IsTrue(bool, string) | void | Asserts that the input value must be true | ### Comparisons | Methods | Return Type | Description | | -- | -- | -- | -| IsEqualTo(T, T, string) | void | Asserts that the input value must be equal to a specified value | -| IsBitwiseEqualTo(T, T, string) | void | Asserts that the input value must be a bitwise match with a specified value | -| IsLessThan(T, T, string) | void | Asserts that the input value must be less than a specified value | -| IsLessThanOrEqualTo(T, T, string) | void | Asserts that the input value must be less than or equal to a specified value | -| IsInRange(T, T, T, string) | void | Asserts that the input value must be in a given range | -| IsBetween(T, T, T, string name) | void | Asserts that the input value must be in a given interval | +| IsEqualTo<T>(T, T, string) | void | Asserts that the input value must be equal to a specified value | +| IsBitwiseEqualTo<T>(T, T, string) | void | Asserts that the input value must be a bitwise match with a specified value | +| IsLessThan<T>(T, T, string) | void | Asserts that the input value must be less than a specified value | +| IsLessThanOrEqualTo<T>(T, T, string) | void | Asserts that the input value must be less than or equal to a specified value | +| IsInRange<T>(T, T, T, string) | void | Asserts that the input value must be in a given range | +| IsBetween<T>(T, T, T, string name) | void | Asserts that the input value must be in a given interval | ### Strings @@ -104,11 +104,11 @@ There are dozens of different APIs and overloads in the `Guard` class, here are | Methods | Return Type | Description | | -- | -- | -- | -| IsNotEmpty(T[], string) | void | Asserts that the input array instance must not be empty | -| HasSizeEqualTo(T[], int, string) | void | Asserts that the input array instance must have a size of a specified value | -| HasSizeAtLeast(T[], int, string) | void | Asserts that the input array must have a size of at least or equal to a specified value | -| IsInRangeFor(int, T[], string) | void | Asserts that the input index is valid for a given array | -| HasSizeLessThanOrEqualTo(T[], T[], string) | void | Asserts that the source array must have a size of less than or equal to that of the destination array | +| IsNotEmpty<T>(T[], string) | void | Asserts that the input array instance must not be empty | +| HasSizeEqualTo<T>(T[], int, string) | void | Asserts that the input array instance must have a size of a specified value | +| HasSizeAtLeast<T>(T[], int, string) | void | Asserts that the input array must have a size of at least or equal to a specified value | +| IsInRangeFor<T>(int, T[], string) | void | Asserts that the input index is valid for a given array | +| HasSizeLessThanOrEqualTo<T>(T[], T[], string) | void | Asserts that the source array must have a size of less than or equal to that of the destination array | ### Tasks From 4c11f2622753722a62c9b58743c282f0144e1643 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 11 Mar 2020 01:04:08 +0100 Subject: [PATCH 07/10] Removed word repetition --- docs/developer-tools/Guard.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer-tools/Guard.md b/docs/developer-tools/Guard.md index 86268bb28..c6ce2fe20 100644 --- a/docs/developer-tools/Guard.md +++ b/docs/developer-tools/Guard.md @@ -21,7 +21,7 @@ These `Guard` APIs are built with three core principles in mind: ## Syntax -Here is a sample method, with some checks being done with explicit checks and manual throw statements: +Here is a sample method, with some checks being done with explicitly and with manual throw statements: ```csharp public static void SampleMethod(int[] array, int index, Span span, string text) From 61452b3c9d5538c6683f11aa9cf66b7de32c5d9f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 11 Mar 2020 22:10:19 +0100 Subject: [PATCH 08/10] Added more info on range/interval APIs --- docs/developer-tools/Guard.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/developer-tools/Guard.md b/docs/developer-tools/Guard.md index c6ce2fe20..d7e866f44 100644 --- a/docs/developer-tools/Guard.md +++ b/docs/developer-tools/Guard.md @@ -90,8 +90,9 @@ There are dozens of different APIs and overloads in the `Guard` class, here are | IsBitwiseEqualTo<T>(T, T, string) | void | Asserts that the input value must be a bitwise match with a specified value | | IsLessThan<T>(T, T, string) | void | Asserts that the input value must be less than a specified value | | IsLessThanOrEqualTo<T>(T, T, string) | void | Asserts that the input value must be less than or equal to a specified value | -| IsInRange<T>(T, T, T, string) | void | Asserts that the input value must be in a given range | -| IsBetween<T>(T, T, T, string name) | void | Asserts that the input value must be in a given interval | +| IsInRange<T>(T, T, T, string) | void | Asserts that the input value must be in the [minimum, maximum) range | +| IsBetween<T>(T, T, T, string name) | void | Asserts that the input value must be in the (minimum, maximum) interval | +| IsBetweenOrEqualTo<T>(T, T, T, string name) | void | Asserts that the input value must be in the [minimum, maximum] interval | ### Strings From 32754b29ee45da766835d6552d5321e095a306c7 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 14 May 2020 12:30:28 +0200 Subject: [PATCH 09/10] Updated Guard sample with new naming changes --- docs/developer-tools/Guard.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer-tools/Guard.md b/docs/developer-tools/Guard.md index d7e866f44..afc4b4332 100644 --- a/docs/developer-tools/Guard.md +++ b/docs/developer-tools/Guard.md @@ -59,7 +59,7 @@ And here is the same method, but using the new `Guard.APIs` to validate the inpu public static void SampleMethod(int[] array, int index, Span span, string text) { Guard.IsNotNull(array, nameof(array)); - Guard.HasSizeAtLeast(array, 10, nameof(array)); + Guard.HasSizeGreaterThanOrEqualTo(array, 10, nameof(array)); Guard.IsInRangeFor(index, array, nameof(index)); Guard.HasSizeLessThanOrEqualTo(array, span, nameof(span)); Guard.IsNotNullOrEmpty(text, nameof(text)); From a919c111141daea3b5b9e71b515a31c0d1407463 Mon Sep 17 00:00:00 2001 From: "Michael Hawker MSFT (XAML Llama)" <24302614+michael-hawker@users.noreply.github.com> Date: Fri, 5 Jun 2020 15:10:43 -0700 Subject: [PATCH 10/10] Update docs/developer-tools/Guard.md --- docs/developer-tools/Guard.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer-tools/Guard.md b/docs/developer-tools/Guard.md index afc4b4332..7fe1cd612 100644 --- a/docs/developer-tools/Guard.md +++ b/docs/developer-tools/Guard.md @@ -124,7 +124,7 @@ You can find more examples in our [unit tests](https://github.com/Microsoft/Wind ## Requirements -| Device family | Universal, 10.0.16299.0 or higher | +| Implementation | .NET Standard 2.0 | | --- | --- | | Namespace | Microsoft.Toolkit.Diagnostics | | NuGet package | [Microsoft.Toolkit](https://www.nuget.org/packages/Microsoft.Toolkit/) |