.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
This commit is contained in:
Dmytro Struk
2025-06-04 01:44:12 -07:00
committed by GitHub
Unverified
parent 0bcb11fbb4
commit 41facf3a2d
24 changed files with 1680 additions and 0 deletions
+4
View File
@@ -43,4 +43,8 @@
<_Parameter1>false</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
<!-- Common properties -->
<Import Project="$(MSBuildThisFileDirectory)\eng\MSBuild\LegacySupport.props" />
<Import Project="$(MSBuildThisFileDirectory)\eng\MSBuild\Shared.props" />
</Project>
+2
View File
@@ -10,4 +10,6 @@
<Message Text="Running dotnet format" Importance="high" />
<Exec Command="dotnet format --no-restore -v diag $(ProjectFileName)" />
</Target>
<Import Project="$(MSBuildThisFileDirectory)\eng\MSBuild\Shared.targets" />
</Project>
+36
View File
@@ -20,6 +20,42 @@
<File Path="tests/.editorconfig" />
<File Path="tests/Directory.Build.props" />
</Folder>
<Folder Name="/Solution Items/eng/MSBuild/">
<File Path="eng/MSBuild/LegacySupport.props" />
<File Path="eng/MSBuild/Shared.props" />
<File Path="eng/MSBuild/Shared.targets" />
</Folder>
<Folder Name="/Solution Items/src/Shared/Throw/">
<File Path="src/Shared/Throw/README.md" />
<File Path="src/Shared/Throw/Throw.cs" />
</Folder>
<Folder Name="/Solution Items/src/LegacySupport/">
<File Path="src/LegacySupport/README.md" />
</Folder>
<Folder Name="/Solution Items/src/LegacySupport/CallerAttributes/">
<File Path="src/LegacySupport/CallerAttributes/CallerArgumentExpressionAttribute.cs" />
<File Path="src/LegacySupport/CallerAttributes/README.md" />
</Folder>
<Folder Name="/Solution Items/src/LegacySupport/DiagnosticAttributes/">
<File Path="src/LegacySupport/DiagnosticAttributes/NullableAttributes.cs" />
<File Path="src/LegacySupport/DiagnosticAttributes/README.md" />
</Folder>
<Folder Name="/Solution Items/src/LegacySupport/ExperimentalAttribute/">
<File Path="src/LegacySupport/ExperimentalAttribute/ExperimentalAttribute.cs" />
<File Path="src/LegacySupport/ExperimentalAttribute/README.md" />
</Folder>
<Folder Name="/Solution Items/src/LegacySupport/IsExternalInit/">
<File Path="src/LegacySupport/IsExternalInit/IsExternalInit.cs" />
<File Path="src/LegacySupport/IsExternalInit/README.md" />
</Folder>
<Folder Name="/Solution Items/src/LegacySupport/TrimAttributes/">
<File Path="src/LegacySupport/TrimAttributes/DynamicallyAccessedMembersAttribute.cs" />
<File Path="src/LegacySupport/TrimAttributes/DynamicallyAccessedMemberTypes.cs" />
<File Path="src/LegacySupport/TrimAttributes/README.md" />
<File Path="src/LegacySupport/TrimAttributes/RequiresDynamicCodeAttribute.cs" />
<File Path="src/LegacySupport/TrimAttributes/RequiresUnreferencedCodeAttribute.cs" />
<File Path="src/LegacySupport/TrimAttributes/UnconditionalSuppressMessageAttribute.cs" />
</Folder>
<Project Path="src/Microsoft.Agents.Abstractions/Microsoft.Agents.Abstractions.csproj" />
<Project Path="src/Microsoft.Agents/Microsoft.Agents.csproj" />
<Project Path="tests/Microsoft.Agents.Abstractions.UnitTests/Microsoft.Agents.Abstractions.UnitTests.csproj">
+21
View File
@@ -0,0 +1,21 @@
<Project>
<ItemGroup Condition="'$(InjectDiagnosticAttributesOnLegacy)' == 'true' AND !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
<Compile Include="$(MSBuildThisFileDirectory)\..\..\src\LegacySupport\DiagnosticAttributes\*.cs" LinkBase="LegacySupport\DiagnosticAttributes" />
</ItemGroup>
<ItemGroup Condition="'$(InjectCallerAttributesOnLegacy)' == 'true' AND !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
<Compile Include="$(MSBuildThisFileDirectory)\..\..\src\LegacySupport\CallerAttributes\*.cs" LinkBase="LegacySupport\CallerAttributes" />
</ItemGroup>
<ItemGroup Condition="'$(InjectExperimentalAttributeOnLegacy)' == 'true' AND !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
<Compile Include="$(MSBuildThisFileDirectory)\..\..\src\LegacySupport\ExperimentalAttribute\*.cs" LinkBase="LegacySupport\ExperimentalAttribute" />
</ItemGroup>
<ItemGroup Condition="'$(InjectIsExternalInitOnLegacy)' == 'true' AND !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
<Compile Include="$(MSBuildThisFileDirectory)\..\..\src\LegacySupport\IsExternalInit\*.cs" LinkBase="LegacySupport\IsExternalInit" />
</ItemGroup>
<ItemGroup Condition="'$(InjectTrimAttributesOnLegacy)' == 'true' AND !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
<Compile Include="$(MSBuildThisFileDirectory)\..\..\src\LegacySupport\TrimAttributes\*.cs" LinkBase="LegacySupport\TrimAttributes" />
</ItemGroup>
</Project>
+5
View File
@@ -0,0 +1,5 @@
<Project>
<ItemGroup Condition="'$(InjectSharedThrow)' == 'true'">
<Compile Include="$(MSBuildThisFileDirectory)\..\..\src\Shared\Throw\*.cs" LinkBase="Shared\Throw" />
</ItemGroup>
</Project>
+7
View File
@@ -0,0 +1,7 @@
<Project>
<!-- This configuration is required to automatically inject all dependencies for specific classes. -->
<PropertyGroup Condition="'$(InjectSharedThrow)' == 'true'">
<InjectCallerAttributesOnLegacy Condition="'$(InjectCallerAttributesOnLegacy)' == ''">true</InjectCallerAttributesOnLegacy>
<InjectDiagnosticAttributesOnLegacy Condition="'$(InjectDiagnosticAttributesOnLegacy)' == ''">true</InjectDiagnosticAttributesOnLegacy>
</PropertyGroup>
</Project>
@@ -0,0 +1,27 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Diagnostics.CodeAnalysis;
namespace System.Runtime.CompilerServices;
/// <summary>
/// Tags parameter that should be filled with specific caller name.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class CallerArgumentExpressionAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="CallerArgumentExpressionAttribute"/> class.
/// </summary>
/// <param name="parameterName">Function parameter to take the name from.</param>
public CallerArgumentExpressionAttribute(string parameterName)
{
ParameterName = parameterName;
}
/// <summary>
/// Gets name of the function parameter that name should be taken from.
/// </summary>
public string ParameterName { get; }
}
@@ -0,0 +1,9 @@
# CallerAttributes
To use this source in your project, add the following to your `.csproj` file:
```xml
<PropertyGroup>
<InjectCallerAttributesOnLegacy>true</InjectCallerAttributesOnLegacy>
</PropertyGroup>
```
@@ -0,0 +1,162 @@
// Copyright (c) Microsoft. All rights reserved.
#pragma warning disable CA1019
namespace System.Diagnostics.CodeAnalysis;
#if !NETCOREAPP3_1_OR_GREATER
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class AllowNullAttribute : Attribute
{
}
/// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class DisallowNullAttribute : Attribute
{
}
/// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class MaybeNullAttribute : Attribute
{
}
/// <summary>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.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class NotNullAttribute : Attribute
{
}
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class MaybeNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter may be <see langword="null" />.
/// </param>
public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
}
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class NotNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be <see langword="null" />.
/// </param>
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
}
/// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class NotNullIfNotNullAttribute : Attribute
{
/// <summary>Initializes the attribute with the associated parameter name.</summary>
/// <param name="parameterName">
/// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
/// </param>
public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
/// <summary>Gets the associated parameter name.</summary>
public string ParameterName { get; }
}
/// <summary>Applied to a method that will never return under any circumstance.</summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class DoesNotReturnAttribute : Attribute
{
}
/// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class DoesNotReturnIfAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified parameter value.</summary>
/// <param name="parameterValue">
/// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
/// the associated parameter matches this value.
/// </param>
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
/// <summary>Gets the condition parameter value.</summary>
public bool ParameterValue { get; }
}
#endif
/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values.</summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
[ExcludeFromCodeCoverage]
internal sealed class MemberNotNullAttribute : Attribute
{
/// <summary>Initializes the attribute with a field or property member.</summary>
/// <param name="member">
/// The field or property member that is promised to be not-null.
/// </param>
public MemberNotNullAttribute(string member) => Members = new[] { member };
/// <summary>Initializes the attribute with the list of field and property members.</summary>
/// <param name="members">
/// The list of field and property members that are promised to be not-null.
/// </param>
public MemberNotNullAttribute(params string[] members) => Members = members;
/// <summary>Gets field or property member names.</summary>
public string[] Members { get; }
}
/// <summary>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.</summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
[ExcludeFromCodeCoverage]
internal sealed class MemberNotNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition and a field or property member.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be <see langword="null" />.
/// </param>
/// <param name="member">
/// The field or property member that is promised to be not-null.
/// </param>
public MemberNotNullWhenAttribute(bool returnValue, string member)
{
ReturnValue = returnValue;
Members = new[] { member };
}
/// <summary>Initializes the attribute with the specified return value condition and list of field and property members.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be <see langword="null" />.
/// </param>
/// <param name="members">
/// The list of field and property members that are promised to be not-null.
/// </param>
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
{
ReturnValue = returnValue;
Members = members;
}
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
/// <summary>Gets field or property member names.</summary>
public string[] Members { get; }
}
@@ -0,0 +1,9 @@
# DiagnosticAttributes
To use this source in your project, add the following to your `.csproj` file:
```xml
<PropertyGroup>
<InjectDiagnosticAttributesOnLegacy>true</InjectDiagnosticAttributesOnLegacy>
</PropertyGroup>
```
@@ -0,0 +1,55 @@
// Copyright (c) Microsoft. All rights reserved.
#if !NET8_0_OR_GREATER
namespace System.Diagnostics.CodeAnalysis;
/// <summary>
/// Indicates that an API element is experimental and subject to change without notice.
/// </summary>
[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
{
/// <summary>
/// Initializes a new instance of the <see cref="ExperimentalAttribute"/> class.
/// </summary>
/// <param name="diagnosticId">Human readable explanation for marking experimental API.</param>
public ExperimentalAttribute(string diagnosticId)
{
DiagnosticId = diagnosticId;
}
/// <summary>
/// Gets the ID that the compiler will use when reporting a use of the API the attribute applies to.
/// </summary>
/// <value>The unique diagnostic ID.</value>
/// <remarks>
/// The diagnostic ID is shown in build output for warnings and errors.
/// <para>This property represents the unique ID that can be used to suppress the warnings or errors, if needed.</para>
/// </remarks>
public string DiagnosticId { get; }
/// <summary>
/// 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.
/// </summary>
/// <value>The format string that represents a URL to corresponding documentation.</value>
/// <remarks>An example format string is <c>https://contoso.com/obsoletion-warnings/{0}</c>.</remarks>
#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
@@ -0,0 +1,9 @@
# ExperimentalAttribute
To use this source in your project, add the following to your `.csproj` file:
```xml
<PropertyGroup>
<InjectExperimentalAttributeOnLegacy>true</InjectExperimentalAttributeOnLegacy>
</PropertyGroup>
```
@@ -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
{
}
@@ -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
<PropertyGroup>
<InjectIsExternalInitOnLegacy>true</InjectIsExternalInitOnLegacy>
</PropertyGroup>
```
+8
View File
@@ -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.
@@ -0,0 +1,93 @@
// Copyright (c) Microsoft. All rights reserved.
namespace System.Diagnostics.CodeAnalysis;
/// <summary>
/// Specifies the types of members that are dynamically accessed.
///
/// This enumeration has a <see cref="FlagsAttribute"/> attribute that allows a
/// bitwise combination of its member values.
/// </summary>
[Flags]
internal enum DynamicallyAccessedMemberTypes
{
/// <summary>
/// Specifies no members.
/// </summary>
None = 0,
/// <summary>
/// Specifies the default, parameterless public constructor.
/// </summary>
PublicParameterlessConstructor = 0x0001,
/// <summary>
/// Specifies all public constructors.
/// </summary>
PublicConstructors = 0x0002 | PublicParameterlessConstructor,
/// <summary>
/// Specifies all non-public constructors.
/// </summary>
NonPublicConstructors = 0x0004,
/// <summary>
/// Specifies all public methods.
/// </summary>
PublicMethods = 0x0008,
/// <summary>
/// Specifies all non-public methods.
/// </summary>
NonPublicMethods = 0x0010,
/// <summary>
/// Specifies all public fields.
/// </summary>
PublicFields = 0x0020,
/// <summary>
/// Specifies all non-public fields.
/// </summary>
NonPublicFields = 0x0040,
/// <summary>
/// Specifies all public nested types.
/// </summary>
PublicNestedTypes = 0x0080,
/// <summary>
/// Specifies all non-public nested types.
/// </summary>
NonPublicNestedTypes = 0x0100,
/// <summary>
/// Specifies all public properties.
/// </summary>
PublicProperties = 0x0200,
/// <summary>
/// Specifies all non-public properties.
/// </summary>
NonPublicProperties = 0x0400,
/// <summary>
/// Specifies all public events.
/// </summary>
PublicEvents = 0x0800,
/// <summary>
/// Specifies all non-public events.
/// </summary>
NonPublicEvents = 0x1000,
/// <summary>
/// Specifies all interfaces implemented by the type.
/// </summary>
Interfaces = 0x2000,
/// <summary>
/// Specifies all members.
/// </summary>
All = ~None
}
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft. All rights reserved.
namespace System.Diagnostics.CodeAnalysis;
/// <summary>
/// Indicates that certain members on a specified <see cref="Type"/> are accessed dynamically,
/// for example through <see cref="System.Reflection"/>.
/// </summary>
/// <remarks>
/// 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 <see cref="Type"/> or <see cref="string"/>.
///
/// When this attribute is applied to a location of type <see cref="string"/>, 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 <see cref="Type"/> instances returned from calling
/// <see cref="object.GetType"/> 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).
/// </remarks>
[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
{
/// <summary>
/// Initializes a new instance of the <see cref="DynamicallyAccessedMembersAttribute"/> class
/// with the specified member types.
/// </summary>
/// <param name="memberTypes">The types of members dynamically accessed.</param>
public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes)
{
MemberTypes = memberTypes;
}
/// <summary>
/// Gets the <see cref="DynamicallyAccessedMemberTypes"/> which specifies the type
/// of members dynamically accessed.
/// </summary>
public DynamicallyAccessedMemberTypes MemberTypes { get; }
}
@@ -0,0 +1,9 @@
# TrimAttributes
To use this source in your project, add the following to your `.csproj` file:
```xml
<PropertyGroup>
<InjectTrimAttributesOnLegacy>true</InjectTrimAttributesOnLegacy>
</PropertyGroup>
```
@@ -0,0 +1,38 @@
// Copyright (c) Microsoft. All rights reserved.
namespace System.Diagnostics.CodeAnalysis;
/// <summary>
/// Indicates that the specified method requires the ability to generate new code at runtime,
/// for example through <see cref="Reflection"/>.
/// </summary>
/// <remarks>
/// This allows tools to understand which methods are unsafe to call when compiling ahead of time.
/// </remarks>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class RequiresDynamicCodeAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="RequiresDynamicCodeAttribute"/> class
/// with the specified message.
/// </summary>
/// <param name="message">
/// A message that contains information about the usage of dynamic code.
/// </param>
public RequiresDynamicCodeAttribute(string message)
{
Message = message;
}
/// <summary>
/// Gets a message that contains information about the usage of dynamic code.
/// </summary>
public string Message { get; }
/// <summary>
/// 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.
/// </summary>
public string? Url { get; set; }
}
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft. All rights reserved.
namespace System.Diagnostics.CodeAnalysis;
/// <summary>
/// Indicates that the specified method requires dynamic access to code that is not referenced
/// statically, for example through <see cref="System.Reflection"/>.
/// </summary>
/// <remarks>
/// This allows tools to understand which methods are unsafe to call when removing unreferenced
/// code from an application.
/// </remarks>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class RequiresUnreferencedCodeAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="RequiresUnreferencedCodeAttribute"/> class
/// with the specified message.
/// </summary>
/// <param name="message">
/// A message that contains information about the usage of unreferenced code.
/// </param>
public RequiresUnreferencedCodeAttribute(string message)
{
Message = message;
}
/// <summary>
/// Gets a message that contains information about the usage of unreferenced code.
/// </summary>
public string Message { get; }
/// <summary>
/// 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.
/// </summary>
public string? Url { get; set; }
}
@@ -0,0 +1,84 @@
// Copyright (c) Microsoft. All rights reserved.
namespace System.Diagnostics.CodeAnalysis;
/// <summary>
/// /// Suppresses reporting of a specific rule violation, allowing multiple suppressions on a
/// single code artifact.
/// </summary>
/// <remarks>
/// <see cref="UnconditionalSuppressMessageAttribute"/> is different than
/// <see cref="SuppressMessageAttribute"/> in that it doesn't have a
/// <see cref="ConditionalAttribute"/>. So it is always preserved in the compiled assembly.
/// </remarks>
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
[ExcludeFromCodeCoverage]
internal sealed class UnconditionalSuppressMessageAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="UnconditionalSuppressMessageAttribute"/>
/// class, specifying the category of the tool and the identifier for an analysis rule.
/// </summary>
/// <param name="category">The category for the attribute.</param>
/// <param name="checkId">The identifier of the analysis rule the attribute applies to.</param>
public UnconditionalSuppressMessageAttribute(string category, string checkId)
{
Category = category;
CheckId = checkId;
}
/// <summary>
/// Gets the category identifying the classification of the attribute.
/// </summary>
/// <remarks>
/// The <see cref="Category"/> property describes the tool or tool analysis category
/// for which a message suppression attribute applies.
/// </remarks>
public string Category { get; }
/// <summary>
/// Gets the identifier of the analysis tool rule to be suppressed.
/// </summary>
/// <remarks>
/// Concatenated together, the <see cref="Category"/> and <see cref="CheckId"/>
/// properties form a unique check identifier.
/// </remarks>
public string CheckId { get; }
/// <summary>
/// Gets or sets the scope of the code that is relevant for the attribute.
/// </summary>
/// <remarks>
/// The Scope property is an optional argument that specifies the metadata scope for which
/// the attribute is relevant.
/// </remarks>
public string? Scope { get; set; }
/// <summary>
/// Gets or sets a fully qualified path that represents the target of the attribute.
/// </summary>
/// <remarks>
/// The <see cref="Target"/> 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.
/// </remarks>
public string? Target { get; set; }
/// <summary>
/// Gets or sets an optional argument expanding on exclusion criteria.
/// </summary>
/// <remarks>
/// The <see cref="MessageId"/> property is an optional argument that specifies additional
/// exclusion where the literal metadata target is not sufficiently precise. For example,
/// the <see cref="UnconditionalSuppressMessageAttribute"/> 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.
/// </remarks>
public string? MessageId { get; set; }
/// <summary>
/// Gets or sets the justification for suppressing the code analysis message.
/// </summary>
public string? Justification { get; set; }
}
@@ -6,6 +6,10 @@
<VersionSuffix>alpha</VersionSuffix>
</PropertyGroup>
<PropertyGroup>
<InjectSharedThrow>true</InjectSharedThrow>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<TargetFrameworks>$(ProjectsDebugTargetFrameworks)</TargetFrameworks>
</PropertyGroup>
+11
View File
@@ -0,0 +1,11 @@
# Throw
Efficient exception throwing utilities.
To use this in your project, add the following to your `.csproj` file:
```xml
<PropertyGroup>
<InjectSharedThrow>true</InjectSharedThrow>
</PropertyGroup>
```
+978
View File
@@ -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;
/// <summary>
/// Defines static methods used to throw exceptions.
/// </summary>
/// <remarks>
/// The main purpose is to reduce code size, improve performance, and standardize exception
/// messages.
/// </remarks>
[ExcludeFromCodeCoverage]
internal static partial class Throw
{
#region For Object
/// <summary>
/// Throws an <see cref="System.ArgumentNullException"/> if the specified argument is <see langword="null"/>.
/// </summary>
/// <typeparam name="T">Argument type to be checked for <see langword="null"/>.</typeparam>
/// <param name="argument">Object to be checked for <see langword="null"/>.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[return: NotNull]
public static T IfNull<T>([NotNull] T argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
{
if (argument is null)
{
ArgumentNullException(paramName);
}
return argument;
}
/// <summary>
/// Throws an <see cref="System.ArgumentNullException"/> if the specified argument is <see langword="null"/>,
/// or <see cref="System.ArgumentException" /> if the specified member is <see langword="null"/>.
/// </summary>
/// <typeparam name="TParameter">Argument type to be checked for <see langword="null"/>.</typeparam>
/// <typeparam name="TMember">Member type to be checked for <see langword="null"/>.</typeparam>
/// <param name="argument">Argument to be checked for <see langword="null"/>.</param>
/// <param name="member">Object member to be checked for <see langword="null"/>.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <param name="memberName">The name of the member.</param>
/// <returns>The original value of <paramref name="member"/>.</returns>
/// <example>
/// <code language="csharp">
/// Throws.IfNullOrMemberNull(myObject, myObject?.MyProperty)
/// </code>
/// </example>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[return: NotNull]
public static TMember IfNullOrMemberNull<TParameter, TMember>(
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentException" /> if the specified member is <see langword="null"/>.
/// </summary>
/// <typeparam name="TParameter">Argument type.</typeparam>
/// <typeparam name="TMember">Member type to be checked for <see langword="null"/>.</typeparam>
/// <param name="argument">Argument to which member belongs.</param>
/// <param name="member">Object member to be checked for <see langword="null"/>.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <param name="memberName">The name of the member.</param>
/// <returns>The original value of <paramref name="member"/>.</returns>
/// <example>
/// <code language="csharp">
/// Throws.IfMemberNull(myObject, myObject.MyProperty)
/// </code>
/// </example>
[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, TMember>(
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
/// <summary>
/// Throws either an <see cref="System.ArgumentNullException"/> or an <see cref="System.ArgumentException"/>
/// if the specified string is <see langword="null"/> or whitespace respectively.
/// </summary>
/// <param name="argument">String to be checked for <see langword="null"/> or whitespace.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentNullException"/> if the string is <see langword="null"/>,
/// or <see cref="System.ArgumentException"/> if it is empty.
/// </summary>
/// <param name="argument">String to be checked for <see langword="null"/> or empty.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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
/// <summary>
/// Throws an <see cref="System.ArgumentException"/> if the argument's buffer size is less than the required buffer size.
/// </summary>
/// <param name="bufferSize">The actual buffer size.</param>
/// <param name="requiredSize">The required buffer size.</param>
/// <param name="paramName">The name of the parameter to be checked.</param>
[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
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the enum value is not valid.
/// </summary>
/// <param name="argument">The argument to evaluate.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <typeparam name="T">The type of the enumeration.</typeparam>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T IfOutOfRange<T>(T argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
where T : struct, Enum
{
#if NET5_0_OR_GREATER
if (!Enum.IsDefined<T>(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
/// <summary>
/// Throws an <see cref="System.ArgumentNullException"/> if the collection is <see langword="null"/>,
/// or <see cref="System.ArgumentException"/> if it is empty.
/// </summary>
/// <param name="argument">The collection to evaluate.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <typeparam name="T">The type of objects in the collection.</typeparam>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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<T> IfNullOrEmpty<T>([NotNull] IEnumerable<T>? argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
{
if (argument == null)
{
ArgumentNullException(paramName);
}
else
{
switch (argument)
{
case ICollection<T> collection:
if (collection.Count == 0)
{
ArgumentException(paramName, "Collection is empty");
}
break;
case IReadOnlyCollection<T> readOnlyCollection:
if (readOnlyCollection.Count == 0)
{
ArgumentException(paramName, "Collection is empty");
}
break;
default:
using (IEnumerator<T> enumerator = argument.GetEnumerator())
{
if (!enumerator.MoveNext())
{
ArgumentException(paramName, "Collection is empty");
}
}
break;
}
}
return argument;
}
#endregion
#region Exceptions
/// <summary>
/// Throws an <see cref="System.ArgumentNullException"/>.
/// </summary>
/// <param name="paramName">The name of the parameter that caused the exception.</param>
#if !NET6_0_OR_GREATER
[MethodImpl(MethodImplOptions.NoInlining)]
#endif
[DoesNotReturn]
public static void ArgumentNullException(string paramName)
=> throw new ArgumentNullException(paramName);
/// <summary>
/// Throws an <see cref="System.ArgumentNullException"/>.
/// </summary>
/// <param name="paramName">The name of the parameter that caused the exception.</param>
/// <param name="message">A message that describes the error.</param>
#if !NET6_0_OR_GREATER
[MethodImpl(MethodImplOptions.NoInlining)]
#endif
[DoesNotReturn]
public static void ArgumentNullException(string paramName, string? message)
=> throw new ArgumentNullException(paramName, message);
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/>.
/// </summary>
/// <param name="paramName">The name of the parameter that caused the exception.</param>
#if !NET6_0_OR_GREATER
[MethodImpl(MethodImplOptions.NoInlining)]
#endif
[DoesNotReturn]
public static void ArgumentOutOfRangeException(string paramName)
=> throw new ArgumentOutOfRangeException(paramName);
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/>.
/// </summary>
/// <param name="paramName">The name of the parameter that caused the exception.</param>
/// <param name="message">A message that describes the error.</param>
#if !NET6_0_OR_GREATER
[MethodImpl(MethodImplOptions.NoInlining)]
#endif
[DoesNotReturn]
public static void ArgumentOutOfRangeException(string paramName, string? message)
=> throw new ArgumentOutOfRangeException(paramName, message);
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/>.
/// </summary>
/// <param name="paramName">The name of the parameter that caused the exception.</param>
/// <param name="actualValue">The value of the argument that caused this exception.</param>
/// <param name="message">A message that describes the error.</param>
#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);
/// <summary>
/// Throws an <see cref="System.ArgumentException"/>.
/// </summary>
/// <param name="paramName">The name of the parameter that caused the exception.</param>
/// <param name="message">A message that describes the error.</param>
#if !NET6_0_OR_GREATER
[MethodImpl(MethodImplOptions.NoInlining)]
#endif
[DoesNotReturn]
public static void ArgumentException(string paramName, string? message)
=> throw new ArgumentException(message, paramName);
/// <summary>
/// Throws an <see cref="System.ArgumentException"/>.
/// </summary>
/// <param name="paramName">The name of the parameter that caused the exception.</param>
/// <param name="message">A message that describes the error.</param>
/// <param name="innerException">The exception that is the cause of the current exception.</param>
/// <remarks>
/// If the <paramref name="innerException"/> is not a <see langword="null"/>, the current exception is raised in a catch
/// block that handles the inner exception.
/// </remarks>
#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);
/// <summary>
/// Throws an <see cref="System.InvalidOperationException"/>.
/// </summary>
/// <param name="message">A message that describes the error.</param>
#if !NET6_0_OR_GREATER
[MethodImpl(MethodImplOptions.NoInlining)]
#endif
[DoesNotReturn]
public static void InvalidOperationException(string message)
=> throw new InvalidOperationException(message);
/// <summary>
/// Throws an <see cref="System.InvalidOperationException"/>.
/// </summary>
/// <param name="message">A message that describes the error.</param>
/// <param name="innerException">The exception that is the cause of the current exception.</param>
#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
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is less than min.
/// </summary>
/// <param name="argument">Number to be expected being less than min.</param>
/// <param name="min">The number that must be less than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is greater than max.
/// </summary>
/// <param name="argument">Number to be expected being greater than max.</param>
/// <param name="max">The number that must be greater than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is less or equal than min.
/// </summary>
/// <param name="argument">Number to be expected being less or equal than min.</param>
/// <param name="min">The number that must be less or equal than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is greater or equal than max.
/// </summary>
/// <param name="argument">Number to be expected being greater or equal than max.</param>
/// <param name="max">The number that must be greater or equal than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is not in the specified range.
/// </summary>
/// <param name="argument">Number to be expected being greater or equal than max.</param>
/// <param name="min">The lower bound of the allowed range of argument values.</param>
/// <param name="max">The upper bound of the allowed range of argument values.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is equal to 0.
/// </summary>
/// <param name="argument">Number to be expected being not equal to zero.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is less than min.
/// </summary>
/// <param name="argument">Number to be expected being less than min.</param>
/// <param name="min">The number that must be less than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is greater than max.
/// </summary>
/// <param name="argument">Number to be expected being greater than max.</param>
/// <param name="max">The number that must be greater than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is less or equal than min.
/// </summary>
/// <param name="argument">Number to be expected being less or equal than min.</param>
/// <param name="min">The number that must be less or equal than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is greater or equal than max.
/// </summary>
/// <param name="argument">Number to be expected being greater or equal than max.</param>
/// <param name="max">The number that must be greater or equal than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is not in the specified range.
/// </summary>
/// <param name="argument">Number to be expected being greater or equal than max.</param>
/// <param name="min">The lower bound of the allowed range of argument values.</param>
/// <param name="max">The upper bound of the allowed range of argument values.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is equal to 0.
/// </summary>
/// <param name="argument">Number to be expected being not equal to zero.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is less than min.
/// </summary>
/// <param name="argument">Number to be expected being less than min.</param>
/// <param name="min">The number that must be less than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is greater than max.
/// </summary>
/// <param name="argument">Number to be expected being greater than max.</param>
/// <param name="max">The number that must be greater than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is less or equal than min.
/// </summary>
/// <param name="argument">Number to be expected being less or equal than min.</param>
/// <param name="min">The number that must be less or equal than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is greater or equal than max.
/// </summary>
/// <param name="argument">Number to be expected being greater or equal than max.</param>
/// <param name="max">The number that must be greater or equal than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is not in the specified range.
/// </summary>
/// <param name="argument">Number to be expected being greater or equal than max.</param>
/// <param name="min">The lower bound of the allowed range of argument values.</param>
/// <param name="max">The upper bound of the allowed range of argument values.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is equal to 0.
/// </summary>
/// <param name="argument">Number to be expected being not equal to zero.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is less than min.
/// </summary>
/// <param name="argument">Number to be expected being less than min.</param>
/// <param name="min">The number that must be less than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is greater than max.
/// </summary>
/// <param name="argument">Number to be expected being greater than max.</param>
/// <param name="max">The number that must be greater than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is less or equal than min.
/// </summary>
/// <param name="argument">Number to be expected being less or equal than min.</param>
/// <param name="min">The number that must be less or equal than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is greater or equal than max.
/// </summary>
/// <param name="argument">Number to be expected being greater or equal than max.</param>
/// <param name="max">The number that must be greater or equal than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is not in the specified range.
/// </summary>
/// <param name="argument">Number to be expected being greater or equal than max.</param>
/// <param name="min">The lower bound of the allowed range of argument values.</param>
/// <param name="max">The upper bound of the allowed range of argument values.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is equal to 0.
/// </summary>
/// <param name="argument">Number to be expected being not equal to zero.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is less than min.
/// </summary>
/// <param name="argument">Number to be expected being less than min.</param>
/// <param name="min">The number that must be less than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is greater than max.
/// </summary>
/// <param name="argument">Number to be expected being greater than max.</param>
/// <param name="max">The number that must be greater than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is less or equal than min.
/// </summary>
/// <param name="argument">Number to be expected being less or equal than min.</param>
/// <param name="min">The number that must be less or equal than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is greater or equal than max.
/// </summary>
/// <param name="argument">Number to be expected being greater or equal than max.</param>
/// <param name="max">The number that must be greater or equal than the argument.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is not in the specified range.
/// </summary>
/// <param name="argument">Number to be expected being greater or equal than max.</param>
/// <param name="min">The lower bound of the allowed range of argument values.</param>
/// <param name="max">The upper bound of the allowed range of argument values.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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;
}
/// <summary>
/// Throws an <see cref="System.ArgumentOutOfRangeException"/> if the specified number is equal to 0.
/// </summary>
/// <param name="argument">Number to be expected being not equal to zero.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[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
}