From 41facf3a2d7e3e6da29afee84012486c265c9cfc Mon Sep 17 00:00:00 2001
From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com>
Date: Wed, 4 Jun 2025 01:44:12 -0700
Subject: [PATCH] .Net: Added shared classes (#58)
* Added Throw shared class
* Added Experimental attribute
* Added IsExternalInit
* Added TrimAttributes
* Small update
* Small update
* Suppress warning
* Added comment
* Updated LegacySupport.props
* Small updates
---
dotnet/Directory.Build.props | 4 +
dotnet/Directory.Build.targets | 2 +
dotnet/agent-framework-dotnet.slnx | 36 +
dotnet/eng/MSBuild/LegacySupport.props | 21 +
dotnet/eng/MSBuild/Shared.props | 5 +
dotnet/eng/MSBuild/Shared.targets | 7 +
.../CallerArgumentExpressionAttribute.cs | 27 +
.../LegacySupport/CallerAttributes/README.md | 9 +
.../NullableAttributes.cs | 162 +++
.../DiagnosticAttributes/README.md | 9 +
.../ExperimentalAttribute.cs | 55 +
.../ExperimentalAttribute/README.md | 9 +
.../IsExternalInit/IsExternalInit.cs | 9 +
.../LegacySupport/IsExternalInit/README.md | 11 +
dotnet/src/LegacySupport/README.md | 8 +
.../DynamicallyAccessedMemberTypes.cs | 93 ++
.../DynamicallyAccessedMembersAttribute.cs | 50 +
.../LegacySupport/TrimAttributes/README.md | 9 +
.../RequiresDynamicCodeAttribute.cs | 38 +
.../RequiresUnreferencedCodeAttribute.cs | 39 +
.../UnconditionalSuppressMessageAttribute.cs | 84 ++
.../Microsoft.Agents.Abstractions.csproj | 4 +
dotnet/src/Shared/Throw/README.md | 11 +
dotnet/src/Shared/Throw/Throw.cs | 978 ++++++++++++++++++
24 files changed, 1680 insertions(+)
create mode 100644 dotnet/eng/MSBuild/LegacySupport.props
create mode 100644 dotnet/eng/MSBuild/Shared.props
create mode 100644 dotnet/eng/MSBuild/Shared.targets
create mode 100644 dotnet/src/LegacySupport/CallerAttributes/CallerArgumentExpressionAttribute.cs
create mode 100644 dotnet/src/LegacySupport/CallerAttributes/README.md
create mode 100644 dotnet/src/LegacySupport/DiagnosticAttributes/NullableAttributes.cs
create mode 100644 dotnet/src/LegacySupport/DiagnosticAttributes/README.md
create mode 100644 dotnet/src/LegacySupport/ExperimentalAttribute/ExperimentalAttribute.cs
create mode 100644 dotnet/src/LegacySupport/ExperimentalAttribute/README.md
create mode 100644 dotnet/src/LegacySupport/IsExternalInit/IsExternalInit.cs
create mode 100644 dotnet/src/LegacySupport/IsExternalInit/README.md
create mode 100644 dotnet/src/LegacySupport/README.md
create mode 100644 dotnet/src/LegacySupport/TrimAttributes/DynamicallyAccessedMemberTypes.cs
create mode 100644 dotnet/src/LegacySupport/TrimAttributes/DynamicallyAccessedMembersAttribute.cs
create mode 100644 dotnet/src/LegacySupport/TrimAttributes/README.md
create mode 100644 dotnet/src/LegacySupport/TrimAttributes/RequiresDynamicCodeAttribute.cs
create mode 100644 dotnet/src/LegacySupport/TrimAttributes/RequiresUnreferencedCodeAttribute.cs
create mode 100644 dotnet/src/LegacySupport/TrimAttributes/UnconditionalSuppressMessageAttribute.cs
create mode 100644 dotnet/src/Shared/Throw/README.md
create mode 100644 dotnet/src/Shared/Throw/Throw.cs
diff --git a/dotnet/Directory.Build.props b/dotnet/Directory.Build.props
index fb3fcfdef2..547ed985e1 100644
--- a/dotnet/Directory.Build.props
+++ b/dotnet/Directory.Build.props
@@ -43,4 +43,8 @@
<_Parameter1>false
+
+
+
+
diff --git a/dotnet/Directory.Build.targets b/dotnet/Directory.Build.targets
index 834abad11b..333f28f2ec 100644
--- a/dotnet/Directory.Build.targets
+++ b/dotnet/Directory.Build.targets
@@ -10,4 +10,6 @@
+
+
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 34e2890d2e..8a13e5e860 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -20,6 +20,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/eng/MSBuild/LegacySupport.props b/dotnet/eng/MSBuild/LegacySupport.props
new file mode 100644
index 0000000000..63edb20cee
--- /dev/null
+++ b/dotnet/eng/MSBuild/LegacySupport.props
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/eng/MSBuild/Shared.props b/dotnet/eng/MSBuild/Shared.props
new file mode 100644
index 0000000000..fdd9e5a802
--- /dev/null
+++ b/dotnet/eng/MSBuild/Shared.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/dotnet/eng/MSBuild/Shared.targets b/dotnet/eng/MSBuild/Shared.targets
new file mode 100644
index 0000000000..5eaa1a08ac
--- /dev/null
+++ b/dotnet/eng/MSBuild/Shared.targets
@@ -0,0 +1,7 @@
+
+
+
+ true
+ true
+
+
diff --git a/dotnet/src/LegacySupport/CallerAttributes/CallerArgumentExpressionAttribute.cs b/dotnet/src/LegacySupport/CallerAttributes/CallerArgumentExpressionAttribute.cs
new file mode 100644
index 0000000000..a406732ed4
--- /dev/null
+++ b/dotnet/src/LegacySupport/CallerAttributes/CallerArgumentExpressionAttribute.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Diagnostics.CodeAnalysis;
+
+namespace System.Runtime.CompilerServices;
+
+///
+/// Tags parameter that should be filled with specific caller name.
+///
+[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class CallerArgumentExpressionAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Function parameter to take the name from.
+ public CallerArgumentExpressionAttribute(string parameterName)
+ {
+ ParameterName = parameterName;
+ }
+
+ ///
+ /// Gets name of the function parameter that name should be taken from.
+ ///
+ public string ParameterName { get; }
+}
diff --git a/dotnet/src/LegacySupport/CallerAttributes/README.md b/dotnet/src/LegacySupport/CallerAttributes/README.md
new file mode 100644
index 0000000000..fa3e9b3b27
--- /dev/null
+++ b/dotnet/src/LegacySupport/CallerAttributes/README.md
@@ -0,0 +1,9 @@
+# CallerAttributes
+
+To use this source in your project, add the following to your `.csproj` file:
+
+```xml
+
+ true
+
+```
diff --git a/dotnet/src/LegacySupport/DiagnosticAttributes/NullableAttributes.cs b/dotnet/src/LegacySupport/DiagnosticAttributes/NullableAttributes.cs
new file mode 100644
index 0000000000..330b365f48
--- /dev/null
+++ b/dotnet/src/LegacySupport/DiagnosticAttributes/NullableAttributes.cs
@@ -0,0 +1,162 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+#pragma warning disable CA1019
+
+namespace System.Diagnostics.CodeAnalysis;
+
+#if !NETCOREAPP3_1_OR_GREATER
+/// Specifies that null is allowed as an input even if the corresponding type disallows it.
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class AllowNullAttribute : Attribute
+{
+}
+
+/// Specifies that null is disallowed as an input even if the corresponding type allows it.
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class DisallowNullAttribute : Attribute
+{
+}
+
+/// Specifies that an output may be null even if the corresponding type disallows it.
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class MaybeNullAttribute : Attribute
+{
+}
+
+/// Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns.
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class NotNullAttribute : Attribute
+{
+}
+
+/// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it.
+[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class MaybeNullWhenAttribute : Attribute
+{
+ /// Initializes the attribute with the specified return value condition.
+ ///
+ /// The return value condition. If the method returns this value, the associated parameter may be .
+ ///
+ public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
+
+ /// Gets the return value condition.
+ public bool ReturnValue { get; }
+}
+
+/// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it.
+[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class NotNullWhenAttribute : Attribute
+{
+ /// Initializes the attribute with the specified return value condition.
+ ///
+ /// The return value condition. If the method returns this value, the associated parameter will not be .
+ ///
+ public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
+
+ /// Gets the return value condition.
+ public bool ReturnValue { get; }
+}
+
+/// Specifies that the output will be non-null if the named parameter is non-null.
+[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class NotNullIfNotNullAttribute : Attribute
+{
+ /// Initializes the attribute with the associated parameter name.
+ ///
+ /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
+ ///
+ public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
+
+ /// Gets the associated parameter name.
+ public string ParameterName { get; }
+}
+
+/// Applied to a method that will never return under any circumstance.
+[AttributeUsage(AttributeTargets.Method, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class DoesNotReturnAttribute : Attribute
+{
+}
+
+/// Specifies that the method will not return if the associated Boolean parameter is passed the specified value.
+[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class DoesNotReturnIfAttribute : Attribute
+{
+ /// Initializes the attribute with the specified parameter value.
+ ///
+ /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
+ /// the associated parameter matches this value.
+ ///
+ public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
+
+ /// Gets the condition parameter value.
+ public bool ParameterValue { get; }
+}
+#endif
+
+/// Specifies that the method or property will ensure that the listed field and property members have not-null values.
+[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
+[ExcludeFromCodeCoverage]
+internal sealed class MemberNotNullAttribute : Attribute
+{
+ /// Initializes the attribute with a field or property member.
+ ///
+ /// The field or property member that is promised to be not-null.
+ ///
+ public MemberNotNullAttribute(string member) => Members = new[] { member };
+
+ /// Initializes the attribute with the list of field and property members.
+ ///
+ /// The list of field and property members that are promised to be not-null.
+ ///
+ public MemberNotNullAttribute(params string[] members) => Members = members;
+
+ /// Gets field or property member names.
+ public string[] Members { get; }
+}
+
+/// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition.
+[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
+[ExcludeFromCodeCoverage]
+internal sealed class MemberNotNullWhenAttribute : Attribute
+{
+ /// Initializes the attribute with the specified return value condition and a field or property member.
+ ///
+ /// The return value condition. If the method returns this value, the associated parameter will not be .
+ ///
+ ///
+ /// The field or property member that is promised to be not-null.
+ ///
+ public MemberNotNullWhenAttribute(bool returnValue, string member)
+ {
+ ReturnValue = returnValue;
+ Members = new[] { member };
+ }
+
+ /// Initializes the attribute with the specified return value condition and list of field and property members.
+ ///
+ /// The return value condition. If the method returns this value, the associated parameter will not be .
+ ///
+ ///
+ /// The list of field and property members that are promised to be not-null.
+ ///
+ public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
+ {
+ ReturnValue = returnValue;
+ Members = members;
+ }
+
+ /// Gets the return value condition.
+ public bool ReturnValue { get; }
+
+ /// Gets field or property member names.
+ public string[] Members { get; }
+}
diff --git a/dotnet/src/LegacySupport/DiagnosticAttributes/README.md b/dotnet/src/LegacySupport/DiagnosticAttributes/README.md
new file mode 100644
index 0000000000..c3dbbeb3d8
--- /dev/null
+++ b/dotnet/src/LegacySupport/DiagnosticAttributes/README.md
@@ -0,0 +1,9 @@
+# DiagnosticAttributes
+
+To use this source in your project, add the following to your `.csproj` file:
+
+```xml
+
+ true
+
+```
diff --git a/dotnet/src/LegacySupport/ExperimentalAttribute/ExperimentalAttribute.cs b/dotnet/src/LegacySupport/ExperimentalAttribute/ExperimentalAttribute.cs
new file mode 100644
index 0000000000..2cac2fb5f6
--- /dev/null
+++ b/dotnet/src/LegacySupport/ExperimentalAttribute/ExperimentalAttribute.cs
@@ -0,0 +1,55 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+#if !NET8_0_OR_GREATER
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// Indicates that an API element is experimental and subject to change without notice.
+///
+[ExcludeFromCodeCoverage]
+[AttributeUsage(
+ AttributeTargets.Class |
+ AttributeTargets.Struct |
+ AttributeTargets.Enum |
+ AttributeTargets.Interface |
+ AttributeTargets.Delegate |
+ AttributeTargets.Method |
+ AttributeTargets.Constructor |
+ AttributeTargets.Property |
+ AttributeTargets.Field |
+ AttributeTargets.Event |
+ AttributeTargets.Assembly)]
+internal sealed class ExperimentalAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Human readable explanation for marking experimental API.
+ public ExperimentalAttribute(string diagnosticId)
+ {
+ DiagnosticId = diagnosticId;
+ }
+
+ ///
+ /// Gets the ID that the compiler will use when reporting a use of the API the attribute applies to.
+ ///
+ /// The unique diagnostic ID.
+ ///
+ /// The diagnostic ID is shown in build output for warnings and errors.
+ /// This property represents the unique ID that can be used to suppress the warnings or errors, if needed.
+ ///
+ public string DiagnosticId { get; }
+
+ ///
+ /// Gets or sets the URL for corresponding documentation.
+ /// The API accepts a format string instead of an actual URL, creating a generic URL that includes the diagnostic ID.
+ ///
+ /// The format string that represents a URL to corresponding documentation.
+ /// An example format string is https://contoso.com/obsoletion-warnings/{0}.
+#pragma warning disable S3996 // URI properties should not be strings
+ public string? UrlFormat { get; set; }
+#pragma warning restore S3996 // URI properties should not be strings
+}
+
+#endif
diff --git a/dotnet/src/LegacySupport/ExperimentalAttribute/README.md b/dotnet/src/LegacySupport/ExperimentalAttribute/README.md
new file mode 100644
index 0000000000..e25614d857
--- /dev/null
+++ b/dotnet/src/LegacySupport/ExperimentalAttribute/README.md
@@ -0,0 +1,9 @@
+# ExperimentalAttribute
+
+To use this source in your project, add the following to your `.csproj` file:
+
+```xml
+
+ true
+
+```
diff --git a/dotnet/src/LegacySupport/IsExternalInit/IsExternalInit.cs b/dotnet/src/LegacySupport/IsExternalInit/IsExternalInit.cs
new file mode 100644
index 0000000000..b340f84592
--- /dev/null
+++ b/dotnet/src/LegacySupport/IsExternalInit/IsExternalInit.cs
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+/* This enables support for C# 9/10 records on older frameworks */
+
+namespace System.Runtime.CompilerServices;
+
+internal static class IsExternalInit
+{
+}
diff --git a/dotnet/src/LegacySupport/IsExternalInit/README.md b/dotnet/src/LegacySupport/IsExternalInit/README.md
new file mode 100644
index 0000000000..871f7e9558
--- /dev/null
+++ b/dotnet/src/LegacySupport/IsExternalInit/README.md
@@ -0,0 +1,11 @@
+# IsExternalInit
+
+Enables use of C# record types on older frameworks.
+
+To use this source in your project, add the following to your `.csproj` file:
+
+```xml
+
+ true
+
+```
diff --git a/dotnet/src/LegacySupport/README.md b/dotnet/src/LegacySupport/README.md
new file mode 100644
index 0000000000..ddc416aae2
--- /dev/null
+++ b/dotnet/src/LegacySupport/README.md
@@ -0,0 +1,8 @@
+# About this Folder
+
+This folder contains a bunch of sources copied from newer versions of .NET which we pull in to
+our sources as necessary. This enables us to compile source code that depends on these newer
+features from .NET even when targeting older frameworks.
+
+Please see the `eng/MSBuild/LegacySupport.props` file for the set of project properties that control importing
+these source files into your project.
diff --git a/dotnet/src/LegacySupport/TrimAttributes/DynamicallyAccessedMemberTypes.cs b/dotnet/src/LegacySupport/TrimAttributes/DynamicallyAccessedMemberTypes.cs
new file mode 100644
index 0000000000..15f7505691
--- /dev/null
+++ b/dotnet/src/LegacySupport/TrimAttributes/DynamicallyAccessedMemberTypes.cs
@@ -0,0 +1,93 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// Specifies the types of members that are dynamically accessed.
+///
+/// This enumeration has a attribute that allows a
+/// bitwise combination of its member values.
+///
+[Flags]
+internal enum DynamicallyAccessedMemberTypes
+{
+ ///
+ /// Specifies no members.
+ ///
+ None = 0,
+
+ ///
+ /// Specifies the default, parameterless public constructor.
+ ///
+ PublicParameterlessConstructor = 0x0001,
+
+ ///
+ /// Specifies all public constructors.
+ ///
+ PublicConstructors = 0x0002 | PublicParameterlessConstructor,
+
+ ///
+ /// Specifies all non-public constructors.
+ ///
+ NonPublicConstructors = 0x0004,
+
+ ///
+ /// Specifies all public methods.
+ ///
+ PublicMethods = 0x0008,
+
+ ///
+ /// Specifies all non-public methods.
+ ///
+ NonPublicMethods = 0x0010,
+
+ ///
+ /// Specifies all public fields.
+ ///
+ PublicFields = 0x0020,
+
+ ///
+ /// Specifies all non-public fields.
+ ///
+ NonPublicFields = 0x0040,
+
+ ///
+ /// Specifies all public nested types.
+ ///
+ PublicNestedTypes = 0x0080,
+
+ ///
+ /// Specifies all non-public nested types.
+ ///
+ NonPublicNestedTypes = 0x0100,
+
+ ///
+ /// Specifies all public properties.
+ ///
+ PublicProperties = 0x0200,
+
+ ///
+ /// Specifies all non-public properties.
+ ///
+ NonPublicProperties = 0x0400,
+
+ ///
+ /// Specifies all public events.
+ ///
+ PublicEvents = 0x0800,
+
+ ///
+ /// Specifies all non-public events.
+ ///
+ NonPublicEvents = 0x1000,
+
+ ///
+ /// Specifies all interfaces implemented by the type.
+ ///
+ Interfaces = 0x2000,
+
+ ///
+ /// Specifies all members.
+ ///
+ All = ~None
+}
diff --git a/dotnet/src/LegacySupport/TrimAttributes/DynamicallyAccessedMembersAttribute.cs b/dotnet/src/LegacySupport/TrimAttributes/DynamicallyAccessedMembersAttribute.cs
new file mode 100644
index 0000000000..0698067c11
--- /dev/null
+++ b/dotnet/src/LegacySupport/TrimAttributes/DynamicallyAccessedMembersAttribute.cs
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// Indicates that certain members on a specified are accessed dynamically,
+/// for example through .
+///
+///
+/// This allows tools to understand which members are being accessed during the execution
+/// of a program.
+///
+/// This attribute is valid on members whose type is or .
+///
+/// When this attribute is applied to a location of type , the assumption is
+/// that the string represents a fully qualified type name.
+///
+/// When this attribute is applied to a class, interface, or struct, the members specified
+/// can be accessed dynamically on instances returned from calling
+/// on instances of that class, interface, or struct.
+///
+/// If the attribute is applied to a method it's treated as a special case and it implies
+/// the attribute should be applied to the "this" parameter of the method. As such the attribute
+/// should only be used on instance methods of types assignable to System.Type (or string, but no methods
+/// will use it there).
+///
+[AttributeUsage(
+ AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
+ AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method |
+ AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct,
+ Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class DynamicallyAccessedMembersAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the class
+ /// with the specified member types.
+ ///
+ /// The types of members dynamically accessed.
+ public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes)
+ {
+ MemberTypes = memberTypes;
+ }
+
+ ///
+ /// Gets the which specifies the type
+ /// of members dynamically accessed.
+ ///
+ public DynamicallyAccessedMemberTypes MemberTypes { get; }
+}
diff --git a/dotnet/src/LegacySupport/TrimAttributes/README.md b/dotnet/src/LegacySupport/TrimAttributes/README.md
new file mode 100644
index 0000000000..2774498901
--- /dev/null
+++ b/dotnet/src/LegacySupport/TrimAttributes/README.md
@@ -0,0 +1,9 @@
+# TrimAttributes
+
+To use this source in your project, add the following to your `.csproj` file:
+
+```xml
+
+ true
+
+```
diff --git a/dotnet/src/LegacySupport/TrimAttributes/RequiresDynamicCodeAttribute.cs b/dotnet/src/LegacySupport/TrimAttributes/RequiresDynamicCodeAttribute.cs
new file mode 100644
index 0000000000..b593fc1761
--- /dev/null
+++ b/dotnet/src/LegacySupport/TrimAttributes/RequiresDynamicCodeAttribute.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// Indicates that the specified method requires the ability to generate new code at runtime,
+/// for example through .
+///
+///
+/// This allows tools to understand which methods are unsafe to call when compiling ahead of time.
+///
+[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class RequiresDynamicCodeAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the class
+ /// with the specified message.
+ ///
+ ///
+ /// A message that contains information about the usage of dynamic code.
+ ///
+ public RequiresDynamicCodeAttribute(string message)
+ {
+ Message = message;
+ }
+
+ ///
+ /// Gets a message that contains information about the usage of dynamic code.
+ ///
+ public string Message { get; }
+
+ ///
+ /// Gets or sets an optional URL that contains more information about the method,
+ /// why it requires dynamic code, and what options a consumer has to deal with it.
+ ///
+ public string? Url { get; set; }
+}
diff --git a/dotnet/src/LegacySupport/TrimAttributes/RequiresUnreferencedCodeAttribute.cs b/dotnet/src/LegacySupport/TrimAttributes/RequiresUnreferencedCodeAttribute.cs
new file mode 100644
index 0000000000..8b116ff2bc
--- /dev/null
+++ b/dotnet/src/LegacySupport/TrimAttributes/RequiresUnreferencedCodeAttribute.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// Indicates that the specified method requires dynamic access to code that is not referenced
+/// statically, for example through .
+///
+///
+/// This allows tools to understand which methods are unsafe to call when removing unreferenced
+/// code from an application.
+///
+[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class RequiresUnreferencedCodeAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the class
+ /// with the specified message.
+ ///
+ ///
+ /// A message that contains information about the usage of unreferenced code.
+ ///
+ public RequiresUnreferencedCodeAttribute(string message)
+ {
+ Message = message;
+ }
+
+ ///
+ /// Gets a message that contains information about the usage of unreferenced code.
+ ///
+ public string Message { get; }
+
+ ///
+ /// Gets or sets an optional URL that contains more information about the method,
+ /// why it requires unreferenced code, and what options a consumer has to deal with it.
+ ///
+ public string? Url { get; set; }
+}
diff --git a/dotnet/src/LegacySupport/TrimAttributes/UnconditionalSuppressMessageAttribute.cs b/dotnet/src/LegacySupport/TrimAttributes/UnconditionalSuppressMessageAttribute.cs
new file mode 100644
index 0000000000..2896a7497f
--- /dev/null
+++ b/dotnet/src/LegacySupport/TrimAttributes/UnconditionalSuppressMessageAttribute.cs
@@ -0,0 +1,84 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// /// Suppresses reporting of a specific rule violation, allowing multiple suppressions on a
+/// single code artifact.
+///
+///
+/// is different than
+/// in that it doesn't have a
+/// . So it is always preserved in the compiled assembly.
+///
+[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
+[ExcludeFromCodeCoverage]
+internal sealed class UnconditionalSuppressMessageAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the
+ /// class, specifying the category of the tool and the identifier for an analysis rule.
+ ///
+ /// The category for the attribute.
+ /// The identifier of the analysis rule the attribute applies to.
+ public UnconditionalSuppressMessageAttribute(string category, string checkId)
+ {
+ Category = category;
+ CheckId = checkId;
+ }
+
+ ///
+ /// Gets the category identifying the classification of the attribute.
+ ///
+ ///
+ /// The property describes the tool or tool analysis category
+ /// for which a message suppression attribute applies.
+ ///
+ public string Category { get; }
+
+ ///
+ /// Gets the identifier of the analysis tool rule to be suppressed.
+ ///
+ ///
+ /// Concatenated together, the and
+ /// properties form a unique check identifier.
+ ///
+ public string CheckId { get; }
+
+ ///
+ /// Gets or sets the scope of the code that is relevant for the attribute.
+ ///
+ ///
+ /// The Scope property is an optional argument that specifies the metadata scope for which
+ /// the attribute is relevant.
+ ///
+ public string? Scope { get; set; }
+
+ ///
+ /// Gets or sets a fully qualified path that represents the target of the attribute.
+ ///
+ ///
+ /// The property is an optional argument identifying the analysis target
+ /// of the attribute. An example value is "System.IO.Stream.ctor():System.Void".
+ /// Because it is fully qualified, it can be long, particularly for targets such as parameters.
+ /// The analysis tool user interface should be capable of automatically formatting the parameter.
+ ///
+ public string? Target { get; set; }
+
+ ///
+ /// Gets or sets an optional argument expanding on exclusion criteria.
+ ///
+ ///
+ /// The property is an optional argument that specifies additional
+ /// exclusion where the literal metadata target is not sufficiently precise. For example,
+ /// the cannot be applied within a method,
+ /// and it may be desirable to suppress a violation against a statement in the method that will
+ /// give a rule violation, but not against all statements in the method.
+ ///
+ public string? MessageId { get; set; }
+
+ ///
+ /// Gets or sets the justification for suppressing the code analysis message.
+ ///
+ public string? Justification { get; set; }
+}
diff --git a/dotnet/src/Microsoft.Agents.Abstractions/Microsoft.Agents.Abstractions.csproj b/dotnet/src/Microsoft.Agents.Abstractions/Microsoft.Agents.Abstractions.csproj
index b66b0fb52f..32d1a766b6 100644
--- a/dotnet/src/Microsoft.Agents.Abstractions/Microsoft.Agents.Abstractions.csproj
+++ b/dotnet/src/Microsoft.Agents.Abstractions/Microsoft.Agents.Abstractions.csproj
@@ -6,6 +6,10 @@
alpha
+
+ true
+
+
$(ProjectsDebugTargetFrameworks)
diff --git a/dotnet/src/Shared/Throw/README.md b/dotnet/src/Shared/Throw/README.md
new file mode 100644
index 0000000000..2c9399864e
--- /dev/null
+++ b/dotnet/src/Shared/Throw/README.md
@@ -0,0 +1,11 @@
+# Throw
+
+Efficient exception throwing utilities.
+
+To use this in your project, add the following to your `.csproj` file:
+
+```xml
+
+ true
+
+```
diff --git a/dotnet/src/Shared/Throw/Throw.cs b/dotnet/src/Shared/Throw/Throw.cs
new file mode 100644
index 0000000000..7de459f145
--- /dev/null
+++ b/dotnet/src/Shared/Throw/Throw.cs
@@ -0,0 +1,978 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+
+namespace Microsoft.Shared.Diagnostics;
+
+///
+/// Defines static methods used to throw exceptions.
+///
+///
+/// The main purpose is to reduce code size, improve performance, and standardize exception
+/// messages.
+///
+[ExcludeFromCodeCoverage]
+internal static partial class Throw
+{
+ #region For Object
+
+ ///
+ /// Throws an if the specified argument is .
+ ///
+ /// Argument type to be checked for .
+ /// Object to be checked for .
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [return: NotNull]
+ public static T IfNull([NotNull] T argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument is null)
+ {
+ ArgumentNullException(paramName);
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified argument is ,
+ /// or if the specified member is .
+ ///
+ /// Argument type to be checked for .
+ /// Member type to be checked for .
+ /// Argument to be checked for .
+ /// Object member to be checked for .
+ /// The name of the parameter being checked.
+ /// The name of the member.
+ /// The original value of .
+ ///
+ ///
+ /// Throws.IfNullOrMemberNull(myObject, myObject?.MyProperty)
+ ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [return: NotNull]
+ public static TMember IfNullOrMemberNull(
+ [NotNull] TParameter argument,
+ [NotNull] TMember member,
+ [CallerArgumentExpression(nameof(argument))] string paramName = "",
+ [CallerArgumentExpression(nameof(member))] string memberName = "")
+ {
+ if (argument is null)
+ {
+ ArgumentNullException(paramName);
+ }
+
+ if (member is null)
+ {
+ ArgumentException(paramName, $"Member {memberName} of {paramName} is null");
+ }
+
+ return member;
+ }
+
+ ///
+ /// Throws an if the specified member is .
+ ///
+ /// Argument type.
+ /// Member type to be checked for .
+ /// Argument to which member belongs.
+ /// Object member to be checked for .
+ /// The name of the parameter being checked.
+ /// The name of the member.
+ /// The original value of .
+ ///
+ ///
+ /// Throws.IfMemberNull(myObject, myObject.MyProperty)
+ ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [return: NotNull]
+ [SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Analyzer isn't seeing the reference to 'argument' in the attribute")]
+ public static TMember IfMemberNull(
+ TParameter argument,
+ [NotNull] TMember member,
+ [CallerArgumentExpression(nameof(argument))] string paramName = "",
+ [CallerArgumentExpression(nameof(member))] string memberName = "")
+ where TParameter : notnull
+ {
+ if (member is null)
+ {
+ ArgumentException(paramName, $"Member {memberName} of {paramName} is null");
+ }
+
+ return member;
+ }
+
+ #endregion
+
+ #region For String
+
+ ///
+ /// Throws either an or an
+ /// if the specified string is or whitespace respectively.
+ ///
+ /// String to be checked for or whitespace.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [return: NotNull]
+ public static string IfNullOrWhitespace([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+#if !NETCOREAPP3_1_OR_GREATER
+ if (argument == null)
+ {
+ ArgumentNullException(paramName);
+ }
+#endif
+
+ if (string.IsNullOrWhiteSpace(argument))
+ {
+ if (argument == null)
+ {
+ ArgumentNullException(paramName);
+ }
+ else
+ {
+ ArgumentException(paramName, "Argument is whitespace");
+ }
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the string is ,
+ /// or if it is empty.
+ ///
+ /// String to be checked for or empty.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [return: NotNull]
+ public static string IfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+#if !NETCOREAPP3_1_OR_GREATER
+ if (argument == null)
+ {
+ ArgumentNullException(paramName);
+ }
+#endif
+
+ if (string.IsNullOrEmpty(argument))
+ {
+ if (argument == null)
+ {
+ ArgumentNullException(paramName);
+ }
+ else
+ {
+ ArgumentException(paramName, "Argument is an empty string");
+ }
+ }
+
+ return argument;
+ }
+
+ #endregion
+
+ #region For Buffer
+
+ ///
+ /// Throws an if the argument's buffer size is less than the required buffer size.
+ ///
+ /// The actual buffer size.
+ /// The required buffer size.
+ /// The name of the parameter to be checked.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void IfBufferTooSmall(int bufferSize, int requiredSize, string paramName = "")
+ {
+ if (bufferSize < requiredSize)
+ {
+ ArgumentException(paramName, $"Buffer too small, needed a size of {requiredSize} but got {bufferSize}");
+ }
+ }
+
+ #endregion
+
+ #region For Enums
+
+ ///
+ /// Throws an if the enum value is not valid.
+ ///
+ /// The argument to evaluate.
+ /// The name of the parameter being checked.
+ /// The type of the enumeration.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T IfOutOfRange(T argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ where T : struct, Enum
+ {
+#if NET5_0_OR_GREATER
+ if (!Enum.IsDefined(argument))
+#else
+ if (!Enum.IsDefined(typeof(T), argument))
+#endif
+ {
+ ArgumentOutOfRangeException(paramName, $"{argument} is an invalid value for enum type {typeof(T)}");
+ }
+
+ return argument;
+ }
+
+ #endregion
+
+ #region For Collections
+
+ ///
+ /// Throws an if the collection is ,
+ /// or if it is empty.
+ ///
+ /// The collection to evaluate.
+ /// The name of the parameter being checked.
+ /// The type of objects in the collection.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [return: NotNull]
+
+ // The method has actually 100% coverage, but due to a bug in the code coverage tool,
+ // a lower number is reported. Therefore, we temporarily exclude this method
+ // from the coverage measurements. Once the bug in the code coverage tool is fixed,
+ // the exclusion attribute can be removed.
+ [ExcludeFromCodeCoverage]
+ public static IEnumerable IfNullOrEmpty([NotNull] IEnumerable? argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument == null)
+ {
+ ArgumentNullException(paramName);
+ }
+ else
+ {
+ switch (argument)
+ {
+ case ICollection collection:
+ if (collection.Count == 0)
+ {
+ ArgumentException(paramName, "Collection is empty");
+ }
+
+ break;
+ case IReadOnlyCollection readOnlyCollection:
+ if (readOnlyCollection.Count == 0)
+ {
+ ArgumentException(paramName, "Collection is empty");
+ }
+
+ break;
+ default:
+ using (IEnumerator enumerator = argument.GetEnumerator())
+ {
+ if (!enumerator.MoveNext())
+ {
+ ArgumentException(paramName, "Collection is empty");
+ }
+ }
+
+ break;
+ }
+ }
+
+ return argument;
+ }
+
+ #endregion
+
+ #region Exceptions
+
+ ///
+ /// Throws an .
+ ///
+ /// The name of the parameter that caused the exception.
+#if !NET6_0_OR_GREATER
+ [MethodImpl(MethodImplOptions.NoInlining)]
+#endif
+ [DoesNotReturn]
+ public static void ArgumentNullException(string paramName)
+ => throw new ArgumentNullException(paramName);
+
+ ///
+ /// Throws an .
+ ///
+ /// The name of the parameter that caused the exception.
+ /// A message that describes the error.
+#if !NET6_0_OR_GREATER
+ [MethodImpl(MethodImplOptions.NoInlining)]
+#endif
+ [DoesNotReturn]
+ public static void ArgumentNullException(string paramName, string? message)
+ => throw new ArgumentNullException(paramName, message);
+
+ ///
+ /// Throws an .
+ ///
+ /// The name of the parameter that caused the exception.
+#if !NET6_0_OR_GREATER
+ [MethodImpl(MethodImplOptions.NoInlining)]
+#endif
+ [DoesNotReturn]
+ public static void ArgumentOutOfRangeException(string paramName)
+ => throw new ArgumentOutOfRangeException(paramName);
+
+ ///
+ /// Throws an .
+ ///
+ /// The name of the parameter that caused the exception.
+ /// A message that describes the error.
+#if !NET6_0_OR_GREATER
+ [MethodImpl(MethodImplOptions.NoInlining)]
+#endif
+ [DoesNotReturn]
+ public static void ArgumentOutOfRangeException(string paramName, string? message)
+ => throw new ArgumentOutOfRangeException(paramName, message);
+
+ ///
+ /// Throws an .
+ ///
+ /// The name of the parameter that caused the exception.
+ /// The value of the argument that caused this exception.
+ /// A message that describes the error.
+#if !NET6_0_OR_GREATER
+ [MethodImpl(MethodImplOptions.NoInlining)]
+#endif
+ [DoesNotReturn]
+ public static void ArgumentOutOfRangeException(string paramName, object? actualValue, string? message)
+ => throw new ArgumentOutOfRangeException(paramName, actualValue, message);
+
+ ///
+ /// Throws an .
+ ///
+ /// The name of the parameter that caused the exception.
+ /// A message that describes the error.
+#if !NET6_0_OR_GREATER
+ [MethodImpl(MethodImplOptions.NoInlining)]
+#endif
+ [DoesNotReturn]
+ public static void ArgumentException(string paramName, string? message)
+ => throw new ArgumentException(message, paramName);
+
+ ///
+ /// Throws an .
+ ///
+ /// The name of the parameter that caused the exception.
+ /// A message that describes the error.
+ /// The exception that is the cause of the current exception.
+ ///
+ /// If the is not a , the current exception is raised in a catch
+ /// block that handles the inner exception.
+ ///
+#if !NET6_0_OR_GREATER
+ [MethodImpl(MethodImplOptions.NoInlining)]
+#endif
+ [DoesNotReturn]
+ public static void ArgumentException(string paramName, string? message, Exception? innerException)
+ => throw new ArgumentException(message, paramName, innerException);
+
+ ///
+ /// Throws an .
+ ///
+ /// A message that describes the error.
+#if !NET6_0_OR_GREATER
+ [MethodImpl(MethodImplOptions.NoInlining)]
+#endif
+ [DoesNotReturn]
+ public static void InvalidOperationException(string message)
+ => throw new InvalidOperationException(message);
+
+ ///
+ /// Throws an .
+ ///
+ /// A message that describes the error.
+ /// The exception that is the cause of the current exception.
+#if !NET6_0_OR_GREATER
+ [MethodImpl(MethodImplOptions.NoInlining)]
+#endif
+ [DoesNotReturn]
+ public static void InvalidOperationException(string message, Exception? innerException)
+ => throw new InvalidOperationException(message, innerException);
+
+ #endregion
+
+ #region For Integer
+
+ ///
+ /// Throws an if the specified number is less than min.
+ ///
+ /// Number to be expected being less than min.
+ /// The number that must be less than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int IfLessThan(int argument, int min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument < min)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument less than minimum value {min}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is greater than max.
+ ///
+ /// Number to be expected being greater than max.
+ /// The number that must be greater than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int IfGreaterThan(int argument, int max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument > max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument greater than maximum value {max}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is less or equal than min.
+ ///
+ /// Number to be expected being less or equal than min.
+ /// The number that must be less or equal than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int IfLessThanOrEqual(int argument, int min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument <= min)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument less or equal than minimum value {min}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is greater or equal than max.
+ ///
+ /// Number to be expected being greater or equal than max.
+ /// The number that must be greater or equal than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int IfGreaterThanOrEqual(int argument, int max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument >= max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument greater or equal than maximum value {max}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is not in the specified range.
+ ///
+ /// Number to be expected being greater or equal than max.
+ /// The lower bound of the allowed range of argument values.
+ /// The upper bound of the allowed range of argument values.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int IfOutOfRange(int argument, int min, int max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument < min || argument > max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument not in the range [{min}..{max}]");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is equal to 0.
+ ///
+ /// Number to be expected being not equal to zero.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int IfZero(int argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument == 0)
+ {
+ ArgumentOutOfRangeException(paramName, "Argument is zero");
+ }
+
+ return argument;
+ }
+
+ #endregion
+
+ #region For Unsigned Integer
+
+ ///
+ /// Throws an if the specified number is less than min.
+ ///
+ /// Number to be expected being less than min.
+ /// The number that must be less than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint IfLessThan(uint argument, uint min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument < min)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument less than minimum value {min}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is greater than max.
+ ///
+ /// Number to be expected being greater than max.
+ /// The number that must be greater than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint IfGreaterThan(uint argument, uint max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument > max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument greater than maximum value {max}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is less or equal than min.
+ ///
+ /// Number to be expected being less or equal than min.
+ /// The number that must be less or equal than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint IfLessThanOrEqual(uint argument, uint min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument <= min)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument less or equal than minimum value {min}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is greater or equal than max.
+ ///
+ /// Number to be expected being greater or equal than max.
+ /// The number that must be greater or equal than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint IfGreaterThanOrEqual(uint argument, uint max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument >= max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument greater or equal than maximum value {max}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is not in the specified range.
+ ///
+ /// Number to be expected being greater or equal than max.
+ /// The lower bound of the allowed range of argument values.
+ /// The upper bound of the allowed range of argument values.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint IfOutOfRange(uint argument, uint min, uint max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument < min || argument > max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument not in the range [{min}..{max}]");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is equal to 0.
+ ///
+ /// Number to be expected being not equal to zero.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint IfZero(uint argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument == 0U)
+ {
+ ArgumentOutOfRangeException(paramName, "Argument is zero");
+ }
+
+ return argument;
+ }
+
+ #endregion
+
+ #region For Long
+
+ ///
+ /// Throws an if the specified number is less than min.
+ ///
+ /// Number to be expected being less than min.
+ /// The number that must be less than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static long IfLessThan(long argument, long min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument < min)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument less than minimum value {min}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is greater than max.
+ ///
+ /// Number to be expected being greater than max.
+ /// The number that must be greater than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static long IfGreaterThan(long argument, long max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument > max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument greater than maximum value {max}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is less or equal than min.
+ ///
+ /// Number to be expected being less or equal than min.
+ /// The number that must be less or equal than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static long IfLessThanOrEqual(long argument, long min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument <= min)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument less or equal than minimum value {min}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is greater or equal than max.
+ ///
+ /// Number to be expected being greater or equal than max.
+ /// The number that must be greater or equal than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static long IfGreaterThanOrEqual(long argument, long max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument >= max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument greater or equal than maximum value {max}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is not in the specified range.
+ ///
+ /// Number to be expected being greater or equal than max.
+ /// The lower bound of the allowed range of argument values.
+ /// The upper bound of the allowed range of argument values.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static long IfOutOfRange(long argument, long min, long max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument < min || argument > max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument not in the range [{min}..{max}]");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is equal to 0.
+ ///
+ /// Number to be expected being not equal to zero.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static long IfZero(long argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument == 0L)
+ {
+ ArgumentOutOfRangeException(paramName, "Argument is zero");
+ }
+
+ return argument;
+ }
+
+ #endregion
+
+ #region For Unsigned Long
+
+ ///
+ /// Throws an if the specified number is less than min.
+ ///
+ /// Number to be expected being less than min.
+ /// The number that must be less than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ulong IfLessThan(ulong argument, ulong min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument < min)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument less than minimum value {min}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is greater than max.
+ ///
+ /// Number to be expected being greater than max.
+ /// The number that must be greater than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ulong IfGreaterThan(ulong argument, ulong max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument > max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument greater than maximum value {max}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is less or equal than min.
+ ///
+ /// Number to be expected being less or equal than min.
+ /// The number that must be less or equal than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ulong IfLessThanOrEqual(ulong argument, ulong min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument <= min)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument less or equal than minimum value {min}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is greater or equal than max.
+ ///
+ /// Number to be expected being greater or equal than max.
+ /// The number that must be greater or equal than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ulong IfGreaterThanOrEqual(ulong argument, ulong max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument >= max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument greater or equal than maximum value {max}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is not in the specified range.
+ ///
+ /// Number to be expected being greater or equal than max.
+ /// The lower bound of the allowed range of argument values.
+ /// The upper bound of the allowed range of argument values.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ulong IfOutOfRange(ulong argument, ulong min, ulong max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument < min || argument > max)
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument not in the range [{min}..{max}]");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is equal to 0.
+ ///
+ /// Number to be expected being not equal to zero.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ulong IfZero(ulong argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ if (argument == 0UL)
+ {
+ ArgumentOutOfRangeException(paramName, "Argument is zero");
+ }
+
+ return argument;
+ }
+
+ #endregion
+
+ #region For Double
+
+ ///
+ /// Throws an if the specified number is less than min.
+ ///
+ /// Number to be expected being less than min.
+ /// The number that must be less than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double IfLessThan(double argument, double min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ // strange conditional needed in order to handle NaN values correctly
+#pragma warning disable S1940 // Boolean checks should not be inverted
+ if (!(argument >= min))
+#pragma warning restore S1940 // Boolean checks should not be inverted
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument less than minimum value {min}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is greater than max.
+ ///
+ /// Number to be expected being greater than max.
+ /// The number that must be greater than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double IfGreaterThan(double argument, double max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ // strange conditional needed in order to handle NaN values correctly
+#pragma warning disable S1940 // Boolean checks should not be inverted
+ if (!(argument <= max))
+#pragma warning restore S1940 // Boolean checks should not be inverted
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument greater than maximum value {max}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is less or equal than min.
+ ///
+ /// Number to be expected being less or equal than min.
+ /// The number that must be less or equal than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double IfLessThanOrEqual(double argument, double min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ // strange conditional needed in order to handle NaN values correctly
+#pragma warning disable S1940 // Boolean checks should not be inverted
+ if (!(argument > min))
+#pragma warning restore S1940 // Boolean checks should not be inverted
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument less or equal than minimum value {min}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is greater or equal than max.
+ ///
+ /// Number to be expected being greater or equal than max.
+ /// The number that must be greater or equal than the argument.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double IfGreaterThanOrEqual(double argument, double max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ // strange conditional needed in order to handle NaN values correctly
+#pragma warning disable S1940 // Boolean checks should not be inverted
+ if (!(argument < max))
+#pragma warning restore S1940 // Boolean checks should not be inverted
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument greater or equal than maximum value {max}");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is not in the specified range.
+ ///
+ /// Number to be expected being greater or equal than max.
+ /// The lower bound of the allowed range of argument values.
+ /// The upper bound of the allowed range of argument values.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double IfOutOfRange(double argument, double min, double max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+ // strange conditional needed in order to handle NaN values correctly
+ if (!(min <= argument && argument <= max))
+ {
+ ArgumentOutOfRangeException(paramName, argument, $"Argument not in the range [{min}..{max}]");
+ }
+
+ return argument;
+ }
+
+ ///
+ /// Throws an if the specified number is equal to 0.
+ ///
+ /// Number to be expected being not equal to zero.
+ /// The name of the parameter being checked.
+ /// The original value of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double IfZero(double argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
+ {
+#pragma warning disable S1244 // Floating point numbers should not be tested for equality
+ if (argument == 0.0)
+#pragma warning restore S1244 // Floating point numbers should not be tested for equality
+ {
+ ArgumentOutOfRangeException(paramName, "Argument is zero");
+ }
+
+ return argument;
+ }
+
+ #endregion
+}