dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.06k stars 4.69k forks source link

The default `ArgumentException` message is misleading #61779

Open IEvangelist opened 2 years ago

IEvangelist commented 2 years ago

Description

When I first saw the message for the ArgumentException I assumed it was mistakenly pulling from the ArgumentOutOfRangeException message. That is not the case, but it could be improved upon nonetheless. I'd like to propose a fix where the default message is something like:

"Specified argument had an unexpected value."

But it's actual value is:

"Value does not fall within the expected range."

Reproduction Steps

To reproduce this, instantiate an ArgumentException with the various .ctor's and evaluate the messages, I've put together a Sharplab.io that provides a bit of contextual output:

using System;

var NewArgErrorZero = () => new ArgumentException();
var NewArgErrorOne = (DateTime date) => new ArgumentException(nameof(date));
var NewArgErrorTwo = (DateTime date) => new ArgumentException(null, nameof(date));

Console.WriteLine(
    $"ArgumentException.ctor():\n  \"{NewArgErrorZero().Message}\"\n");
Console.WriteLine(
    $"ArgumentException.ctor(string? message)\n  \"{NewArgErrorOne(DateTime.Now).Message}\"\n");
Console.WriteLine(
    $"ArgumentException.ctor(string? message, string? paramName):\n  \"{NewArgErrorTwo(DateTime.Now).Message}\"\n");

var NewArgOutOfRangeErrorZero = () => new ArgumentOutOfRangeException();
var NewArgOutOfRangeErrorOne = (DateTime date) => new ArgumentOutOfRangeException(nameof(date));
var NewArgOutOfRangeErrorTwo = (DateTime date) => new ArgumentOutOfRangeException(nameof(date), "Custom message!");

Console.WriteLine(
    $"ArgumentOutOfRangeException.ctor():\n  \"{NewArgOutOfRangeErrorZero().Message}\"\n");
Console.WriteLine(
    $"ArgumentOutOfRangeException.ctor(string? paramName):\n  \"{NewArgOutOfRangeErrorOne(DateTime.Now).Message}\"\n");
Console.WriteLine(
    $"ArgumentOutOfRangeException.ctor(string? paramName, string? message):\n  \"{NewArgOutOfRangeErrorTwo(DateTime.Now).Message}\"\n");

// Output:
//ArgumentException.ctor():
//  "Value does not fall within the expected range."
//
//ArgumentException.ctor(string? message)
//  "date"
//
//ArgumentException.ctor(string? message, string? paramName):
//  "Value does not fall within the expected range. (Parameter 'date')"
//
//ArgumentOutOfRangeException.ctor():
//  "Specified argument was out of the range of valid values."
//
//ArgumentOutOfRangeException.ctor(string? paramName):
//  "Specified argument was out of the range of valid values. (Parameter 'date')"
//
//ArgumentOutOfRangeException.ctor(string? paramName, string? message):
//  "Custom message! (Parameter 'date')"

Expected behavior

I'd expect the default ArgumentException.Message to not mislead consumers by mentioning a value falling within the expected range. That sort of messaging feels appropriate with the ArgumentOutOfRangeException message, but not the ArgumentException.

I'd expect messaging like this:

// "Specified argument had an unexpected value."
new ArgumentException().Message;

// "Specified argument had an unexpected value (Parameter 'exampleParameterName')"
new ArgumentException(null, "exampleParameterName").Message;

Actual behavior

This is the actual behavior:

// "Value does not fall within the expected range."
new ArgumentException().Message;

// "Value does not fall within the expected range. (Parameter 'exampleParameterName')"
new ArgumentException(null, "exampleParameterName").Message;

These values are coming from the src/libraries/System.Private.CoreLib/src/Resources/Strings.resx file:

https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx#L190-L192

And assigned here:

https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/ArgumentException.cs#L95

Regression?

This appears to have been this way for as long as I can tell.

Known Workarounds

You can use the .ctor that allows you to specify a custom message instead.

Configuration

This applies to all.

Other information

No response

dotnet-issue-labeler[bot] commented 2 years ago

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

ghost commented 2 years ago

Tagging subscribers to this area: @dotnet/area-system-runtime See info in area-owners.md if you want to be subscribed.

Issue Details
### Description When I first saw the message for the `ArgumentException` I assumed it was mistakenly pulling from the `ArgumentOutOfRangeException` message. That is _not_ the case, but it could be improved upon nonetheless. I'd like to propose a fix where the default message is something like: > "Specified argument had an unexpected value." But it's actual value is: > "Value does not fall within the expected range." ### Reproduction Steps To reproduce this, instantiate an `ArgumentException` with the various `.ctor`'s and evaluate the messages, I've put together a [Sharplab.io that provides a bit of contextual output](https://sharplab.io/#v2:EYLgtghglgdgNAFxAJwK7wCYgNQB8ACATAIwCwAUBQG4TIAEAcgKYDuAgsgOYCiyyA9sgBaTAXQC8dABQBKCQD46MVnQ6dUYJjATcAHgGMmABwRR+MWQG5qtRqzW8ByAPLKJ0gCIQETACpRNOgxvJjlxRWUWVS4NLR0DY1NzKRgITX4AMylgnxkZa3IaemZ2LkdBXxZ+dykvH39AnNCFJRU1WO09QxMzCxhUABsBuCU0pkzskLyCinxiAE4pCjoVugASACJ2zU6EnvMAOn0EQVkQAB0YFfONgG8Shz5BEQFZA4BZJgBnL4hOJgAvjdLht8rMFktyKt1lsYjt4t0kjAjidkFI5gAGAD8dE0Pz+oUu1zuDzKTxcylqIQaTAODH4LBkH2+v3+QI2ILB5Dmi2Wq022ziXUSvRRp0xOLxrKYIwldCMtDSDDGMguVzoN3u9jJTkq/Cp9QCtPpjOZ+LZwJgoJmhVspM4zlQCGcGQAShAYP9ysJRNVJLIWpFoup4Y7nW6PV69kirDZitqHU6Xe7PUxva4mDU6n4jUEpoG2nC4mHk5G09HeikxhMmtM43ZSonwymveS9VnqbnawWooLtCWI6nhfs+tWsrWRhsAMKoL4nMC4lkEgCE1oo4N5UP5sJDxaTg6jiNFx1OqqJGpJCYHLbT5Je+qZn3NgMta+5EL5KwFRf7+5vw6RMU0TlBVkCVFU1WJLVG2vMt00pbMaTpBlHyXC0OStLkeUhaFv13X9mzgitDhPYDiGxeVFTAZVNFlcjJTQ0JIIvaC1Fgoc2yqA0c00ZDTSfaV2U5G0AHoRLoMMjCdEAKDEvsERFEjUTOWTxLoDYADUIAGVBMwwfhviUfgEDoDJtIGOgWCgBAAAtYDoWzMyYXQjCYY4mAwOgwNTA4NlU1T5IA49lLlKUCRkVSVg2Jo/PIMSAp/BSRyA9F6MXZ86Io0DwM0VVIvUrSdL0gyviMkyzKGSzrLsq5HLoZzXPczzvP+A5pAABSopgfHoAByJpepkWL4rikT5PYw9FORUiVNGqKAGVGqgDIoA8uhaHwkyWAgUr+CdOhMgcmzMxazNDpoAYoE8i7dK+Xz/NG8a/yIo8lPFNLsuoiD8o2Ra3OW1bPI2jotp2g79sOurToOjI6Auq64e0262qkTqwM0Hq6H6kJBuGkSEs2iby1e6aQo+qiaJlOhQsYvK5vUmc534Bcwv+ZcOq6zHsZ8XGgA===): ```csharp using System; var NewArgErrorZero = () => new ArgumentException(); var NewArgErrorOne = (DateTime date) => new ArgumentException(nameof(date)); var NewArgErrorTwo = (DateTime date) => new ArgumentException(null, nameof(date)); Console.WriteLine( $"ArgumentException.ctor():\n \"{NewArgErrorZero().Message}\"\n"); Console.WriteLine( $"ArgumentException.ctor(string? message)\n \"{NewArgErrorOne(DateTime.Now).Message}\"\n"); Console.WriteLine( $"ArgumentException.ctor(string? message, string? paramName):\n \"{NewArgErrorTwo(DateTime.Now).Message}\"\n"); var NewArgOutOfRangeErrorZero = () => new ArgumentOutOfRangeException(); var NewArgOutOfRangeErrorOne = (DateTime date) => new ArgumentOutOfRangeException(nameof(date)); var NewArgOutOfRangeErrorTwo = (DateTime date) => new ArgumentOutOfRangeException(nameof(date), "Custom message!"); Console.WriteLine( $"ArgumentOutOfRangeException.ctor():\n \"{NewArgOutOfRangeErrorZero().Message}\"\n"); Console.WriteLine( $"ArgumentOutOfRangeException.ctor(string? paramName):\n \"{NewArgOutOfRangeErrorOne(DateTime.Now).Message}\"\n"); Console.WriteLine( $"ArgumentOutOfRangeException.ctor(string? paramName, string? message):\n \"{NewArgOutOfRangeErrorTwo(DateTime.Now).Message}\"\n"); // Output: //ArgumentException.ctor(): // "Value does not fall within the expected range." // //ArgumentException.ctor(string? message) // "date" // //ArgumentException.ctor(string? message, string? paramName): // "Value does not fall within the expected range. (Parameter 'date')" // //ArgumentOutOfRangeException.ctor(): // "Specified argument was out of the range of valid values." // //ArgumentOutOfRangeException.ctor(string? paramName): // "Specified argument was out of the range of valid values. (Parameter 'date')" // //ArgumentOutOfRangeException.ctor(string? paramName, string? message): // "Custom message! (Parameter 'date')" ``` ### Expected behavior I'd expect the default `ArgumentException.Message` to _not_ mislead consumers by mentioning a value falling within the expected range. That sort of messaging feels appropriate with the `ArgumentOutOfRangeException` message, but not the `ArgumentException`. I'd expect messaging like this: ```csharp // "Specified argument had an unexpected value." new ArgumentException().Message; // "Specified argument had an unexpected value (Parameter 'exampleParameterName')" new ArgumentException(null, "exampleParameterName").Message; ``` ### Actual behavior This is the actual behavior: ```csharp // "Value does not fall within the expected range." new ArgumentException().Message; // "Value does not fall within the expected range. (Parameter 'exampleParameterName')" new ArgumentException(null, "exampleParameterName").Message; ``` These values are coming from the _src/libraries/System.Private.CoreLib/src/Resources/Strings.resx_ file: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx#L190-L192 And assigned here: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/ArgumentException.cs#L95 ### Regression? This appears to have been this way for as long as I can tell. ### Known Workarounds You can use the `.ctor` that allows you to specify a custom `message` instead. ### Configuration This applies to all. ### Other information _No response_
Author: IEvangelist
Assignees: -
Labels: `area-System.Runtime`, `untriaged`
Milestone: -