Skip to content

Commit 65a78a0

Browse files
CoryCharltonjosesimoes
authored andcommitted
Add null helpers to argument exceptions (#223)
***NO_CI*** (cherry picked from commit 6089c77)
1 parent c33f1ea commit 65a78a0

File tree

5 files changed

+128
-42
lines changed

5 files changed

+128
-42
lines changed

nanoFramework.CoreLibrary.NoReflection/CoreLibrary.NoReflection.nfproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
3838
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
3939
<RestoreLockedMode Condition="'$(TF_BUILD)' == 'True' or '$(ContinuousIntegrationBuild)' == 'True'">true</RestoreLockedMode>
40+
<LangVersion>default</LangVersion>
4041
</PropertyGroup>
4142
<PropertyGroup>
4243
<SignAssembly>true</SignAssembly>

nanoFramework.CoreLibrary/CoreLibrary.nfproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
3939
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
4040
<RestoreLockedMode Condition="'$(TF_BUILD)' == 'True' or '$(ContinuousIntegrationBuild)' == 'True'">true</RestoreLockedMode>
41+
<LangVersion>default</LangVersion>
4142
</PropertyGroup>
4243
<PropertyGroup>
4344
<SignAssembly>true</SignAssembly>

nanoFramework.CoreLibrary/System/ArgumentException.cs

Lines changed: 77 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
// See LICENSE file in the project root for full license information.
55
//
66

7+
#nullable enable
8+
using System.Diagnostics.CodeAnalysis;
9+
using System.Runtime.CompilerServices;
10+
711
namespace System
812
{
913
/// <summary>
@@ -12,54 +16,55 @@ namespace System
1216
[Serializable]
1317
public class ArgumentException : SystemException
1418
{
15-
private String _paramName;
19+
// ReSharper disable InconsistentNaming
20+
private static readonly string Arg_ArgumentException = "Value does not fall within the expected range.";
21+
private static readonly string Arg_ParamName_Name = "(Parameter '%s')";
22+
private static readonly string Argument_EmptyString = "The value cannot be an empty string.";
23+
// ReSharper restore InconsistentNaming
24+
25+
private readonly string? _paramName;
1626

1727
/// <summary>
18-
/// Initializes a new instance of the ArgumentException class.
28+
/// Initializes a new instance of the <see cref="ArgumentException"/> class.
1929
/// </summary>
20-
public ArgumentException()
30+
public ArgumentException(): base(Arg_ArgumentException)
2131
{
2232
}
2333

2434
/// <summary>
25-
/// Initializes a new instance of the ArgumentException class with a specified error message.
35+
/// Initializes a new instance of the <see cref="ArgumentException"/> class with a specified error message.
2636
/// </summary>
27-
/// <param name="message">The error message that explains the reason for the exception. </param>
28-
public ArgumentException(String message)
29-
: base(message)
37+
/// <param name="message">The error message that explains the reason for the exception.</param>
38+
public ArgumentException(string? message) : base(message ?? Arg_ArgumentException)
3039
{
3140
}
3241

3342
/// <summary>
34-
/// Initializes a new instance of the ArgumentException class with a specified error message and a reference to the inner exception that is the cause of this exception.
43+
/// Initializes a new instance of the <see cref="ArgumentException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
3544
/// </summary>
36-
/// <param name="message">The error message that explains the reason for the exception. </param>
37-
/// <param name="innerException">The exception that is the cause of the current exception. If the innerException parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception.</param>
38-
public ArgumentException(String message, Exception innerException)
39-
: base(message, innerException)
45+
/// <param name="message">The error message that explains the reason for the exception.</param>
46+
/// <param name="innerException">The exception that is the cause of the current exception. If the <paramref name="innerException"/> parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception.</param>
47+
public ArgumentException(string? message, Exception? innerException) : base(message ?? Arg_ArgumentException, innerException)
4048
{
4149
}
4250

4351
/// <summary>
44-
/// Initializes a new instance of the ArgumentException class with a specified error message, the parameter name, and a reference to the inner exception that is the cause of this exception.
52+
/// Initializes a new instance of the <see cref="ArgumentException"/> class with a specified error message and the name of the parameter that causes this exception.
4553
/// </summary>
4654
/// <param name="message">The error message that explains the reason for the exception.</param>
47-
/// <param name="paramName">The name of the parameter that caused the current exception. </param>
48-
/// <param name="innerException">The exception that is the cause of the current exception. If the innerException parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. </param>
49-
public ArgumentException(String message, String paramName, Exception innerException)
50-
: base(message, innerException)
55+
/// <param name="paramName">The name of the parameter that caused the current exception.</param>
56+
public ArgumentException(string? message, string? paramName) : base(message ?? Arg_ArgumentException)
5157
{
5258
_paramName = paramName;
5359
}
5460

5561
/// <summary>
56-
/// Initializes a new instance of the ArgumentException class with a specified error message and the name of the parameter that causes this exception.
62+
/// Initializes a new instance of the <see cref="ArgumentException"/> class with a specified error message, the parameter name, and a reference to the inner exception that is the cause of this exception.
5763
/// </summary>
58-
/// <param name="message">The error message that explains the reason for the exception. </param>
59-
/// <param name="paramName">The name of the parameter that caused the current exception. </param>
60-
public ArgumentException(String message, String paramName)
61-
62-
: base(message)
64+
/// <param name="message">The error message that explains the reason for the exception.</param>
65+
/// <param name="paramName">The name of the parameter that caused the current exception.</param>
66+
/// <param name="innerException">The exception that is the cause of the current exception. If the <paramref name="innerException"/> parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception.</param>
67+
public ArgumentException(string? message, string? paramName, Exception? innerException) : base(message ?? Arg_ArgumentException, innerException)
6368
{
6469
_paramName = paramName;
6570
}
@@ -70,27 +75,68 @@ public ArgumentException(String message, String paramName)
7075
/// <value>
7176
/// A text string describing the details of the exception.
7277
/// </value>
73-
public override String Message
78+
public override string Message
7479
{
7580
get
7681
{
7782
var s = base.Message;
78-
if (!(_paramName == null || _paramName.Length == 0))
79-
return s + "\n" + "Invalid argument " + "'" + _paramName + "'";
83+
if (!string.IsNullOrEmpty(_paramName))
84+
{
85+
s += " " + string.Format(Arg_ParamName_Name, _paramName);
86+
}
87+
8088
return s;
8189
}
8290
}
8391

8492
/// <summary>
8593
/// Gets the name of the parameter that causes this exception.
8694
/// </summary>
87-
/// <value>
88-
/// The parameter name.
89-
/// </value>
90-
public virtual String ParamName
95+
/// <value>The parameter name.</value>
96+
public virtual string? ParamName => _paramName;
97+
98+
/// <summary>Throws an exception if <paramref name="argument"/> is null or empty.</summary>
99+
/// <param name="argument">The string argument to validate as non-null and non-empty.</param>
100+
/// <param name="paramName">The name of the parameter with which <paramref name="argument"/> corresponds.</param>
101+
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null.</exception>
102+
/// <exception cref="ArgumentException"><paramref name="argument"/> is empty.</exception>
103+
public static void ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null)
104+
{
105+
if (string.IsNullOrEmpty(argument))
106+
{
107+
ThrowNullOrEmptyException(argument, paramName);
108+
}
109+
}
110+
111+
/* TODO: Implement when string.IsNullOrWhiteSpace exists
112+
/// <summary>Throws an exception if <paramref name="argument"/> is null, empty, or consists only of white-space characters.</summary>
113+
/// <param name="argument">The string argument to validate.</param>
114+
/// <param name="paramName">The name of the parameter with which <paramref name="argument"/> corresponds.</param>
115+
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null.</exception>
116+
/// <exception cref="ArgumentException"><paramref name="argument"/> is empty or consists only of white-space characters.</exception>
117+
public static void ThrowIfNullOrWhiteSpace([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null)
91118
{
92-
get { return _paramName; }
119+
if (string.IsNullOrWhiteSpace(argument))
120+
{
121+
ThrowNullOrWhiteSpaceException(argument, paramName);
122+
}
93123
}
124+
*/
94125

126+
[DoesNotReturn]
127+
private static void ThrowNullOrEmptyException(string? argument, string? paramName)
128+
{
129+
ArgumentNullException.ThrowIfNull(argument, paramName);
130+
throw new ArgumentException(Argument_EmptyString, paramName);
131+
}
132+
133+
/* TODO: Implement when string.IsNullOrWhiteSpace exists
134+
[DoesNotReturn]
135+
private static void ThrowNullOrWhiteSpaceException(string? argument, string? paramName)
136+
{
137+
ArgumentNullException.ThrowIfNull(argument, paramName);
138+
throw new ArgumentException(SR.Argument_EmptyOrWhiteSpaceString, paramName);
139+
}
140+
*/
95141
}
96142
}

nanoFramework.CoreLibrary/System/ArgumentNullException.cs

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
// Portions Copyright (c) Microsoft Corporation. All rights reserved.
44
// See LICENSE file in the project root for full license information.
55
//
6+
7+
#nullable enable
8+
using System.Diagnostics.CodeAnalysis;
9+
using System.Runtime.CompilerServices;
10+
611
namespace System
712
{
813
/// <summary>
@@ -11,23 +16,54 @@ namespace System
1116
[Serializable]
1217
public class ArgumentNullException : ArgumentException
1318
{
19+
// ReSharper disable InconsistentNaming
20+
private static readonly string ArgumentNull_Generic = "Value cannot be null.";
21+
// ReSharper restore InconsistentNaming
22+
23+
/// <summary>
24+
/// Initializes a new instance of the <see cref="ArgumentNullException"/> class.
25+
/// </summary>
26+
public ArgumentNullException(): base(ArgumentNull_Generic)
27+
{
28+
}
29+
1430
/// <summary>
15-
/// Initializes a new instance of the ArgumentNullException class.
31+
/// Initializes a new instance of the <see cref="ArgumentNullException"/> class with the name of the parameter that causes this exception.
1632
/// </summary>
17-
public ArgumentNullException()
18-
{ }
33+
/// <param name="paramName">The name of the parameter that caused the exception.</param>
34+
public ArgumentNullException(string? paramName) : base(ArgumentNull_Generic, paramName)
35+
{
36+
}
1937

2038
/// <summary>
21-
/// Initializes a new instance of the ArgumentNullException class with the name of the parameter that causes this exception.
39+
/// Initializes a new instance of the <see cref="ArgumentNullException"/> class with a specified error message and the exception that is the cause of this exception.
2240
/// </summary>
23-
/// <param name="argument">The name of the parameter that caused the exception.</param>
24-
public ArgumentNullException(string argument) : base(null, argument) { }
41+
/// <param name="message">The error message that explains the reason for this exception.</param>
42+
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>
43+
public ArgumentNullException(string? message, Exception? innerException) : base(message ?? ArgumentNull_Generic, innerException)
44+
{
45+
}
2546

2647
/// <summary>
27-
/// Initializes an instance of the ArgumentNullException class with a specified error message and the name of the parameter that causes this exception.
48+
/// Initializes an instance of the <see cref="ArgumentNullException"/> class with a specified error message and the name of the parameter that causes this exception.
2849
/// </summary>
29-
/// <param name="paramName">The name of the parameter that caused the exception. </param>
30-
/// <param name="message">A message that describes the error. </param>
31-
public ArgumentNullException(String paramName, String message) : base(message, paramName) { }
50+
/// <param name="paramName">The name of the parameter that caused the exception.</param>
51+
/// <param name="message">The error message that explains the reason for this exception.</param>
52+
public ArgumentNullException(string? paramName, string? message) : base(message ?? ArgumentNull_Generic, paramName) { }
53+
54+
/// <summary>Throws an <see cref="ArgumentNullException"/> if <paramref name="argument"/> is null.</summary>
55+
/// <param name="argument">The reference type argument to validate as non-null.</param>
56+
/// <param name="paramName">The name of the parameter with which <paramref name="argument"/> corresponds.</param>
57+
public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null)
58+
{
59+
if (argument is null)
60+
{
61+
Throw(paramName);
62+
}
63+
}
64+
65+
[DoesNotReturn]
66+
internal static void Throw(string? paramName) =>
67+
throw new ArgumentNullException(paramName);
3268
}
3369
}

nanoFramework.CoreLibrary/System/String.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// See LICENSE file in the project root for full license information.
55
//
66

7+
using System.Diagnostics.CodeAnalysis;
8+
79
namespace System
810
{
911
using Runtime.CompilerServices;
@@ -825,7 +827,7 @@ public String PadRight(int totalWidth, char paddingChar = ' ')
825827
/// </summary>
826828
/// <param name="value">The string to test.</param>
827829
/// <returns><see langword="true"/> if the value parameter is <see langword="null"/> or an empty string (""); otherwise, <see langword="false"/>.</returns>
828-
public static bool IsNullOrEmpty(string value)
830+
public static bool IsNullOrEmpty([NotNullWhen(false)] string value)
829831
{
830832
return value == null || value.Length == 0;
831833
}

0 commit comments

Comments
 (0)