-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Standard ArgumentException messages #14487
Comments
I don't think we should be adding exception types for errors that are never to be handled programmatically. Maybe we should just add a static method to create ArgumentException instances for the "empty" case. |
Hmmm... public void Foo(string name, int index)
{
if (name == null)
throw new ArgumentNullException("name");
if (name.Length == 0)
throw new ArgumentEmptyException("name");
if (index < 0 || index >= name.Length)
throw new ArgumentOutOfRangeException("name");
...
} ...versus something like: public void Foo(string name, int index)
{
if (name == null)
throw new ArgumentNullException("name");
if (name.Length == 0)
throw ArgumentException.Empty("name");
if (index < 0 || index >= name.Length)
throw new ArgumentOutOfRangeException("name");
...
} It is a little strange that creating an If a static method for the "Empty" case was added, should static methods be added for "Null" and "OutOfRange" too, to provide a consistent way of creating these, or just live with the inconsistency? public void Foo(string name, int index)
{
if (name == null)
throw ArgumentException.Null("name");
if (name.Length == 0)
throw ArgumentException.Empty("name");
if (index < 0 || index >= name.Length)
throw ArgumentException.OutOfRange("name");
...
} Or perhaps defer and keep this in mind for the possible C# 7 language support for method contracts where there may be scenarios where it is desirable to still throw exceptions vs. failing fast. |
I agree that it's a bit strange, but adding a new type (presumably to the root namespace) so it is less strange does not seem to be a good cost/benefit, especially that parameters that cannot be empty are quite rare. |
@KrzysztofCwalina I wouldn't say that this type of checking is rare at all. Any time you're passing a static string to a method you probably want to check that it is not empty (or whitespace). I've written similar code many, many times. |
I agree with @MgSam, the case doesn't sound rare to me too. |
I honestly feel like the idiom should be: |
adding one more class does not looks like a good solution. 1.Add enumeration that will describe actual reason of the argument inconsistency public enum ArgumentInconsistencyType
{
Null,
Empty,
OutOfRange
} 2.Change |
@stas-sultanov If you write just (I also don't see how can you "handle exception right" when it comes to |
@stas-sultanov, as @KrzysztofCwalina mentions, you shouldn't be catching |
I'd like a simple idiom like this too, but what about the exception message? With that I guess you could pass an empty message like this: if (String.IsNullOrEmpty(value)) {
throw new ArgumentException(string.Empty, nameof(value));
} But then you're still not specifying what is wrong with parameter, leaving it up to the developer to guess or go to the documentation to read that it can't be null or empty. |
@justinvp, I thought about this more. Here is an idea I had:
} then, calling code would look like: |
@KrzysztofCwalina, interesting idea. I like that it allows for adding more "standard messages" in the future without having to add more The enum would be a nested type within if (string.IsNullOrEmpty(value)) {
throw new ArgumentException(ArgumentException.StandardMessage.ArgumentNullOrEmpty, nameof(value));
} Somewhat verbose. I suppose the usage could be made slightly more succinct by shortening the enum value names: if (string.IsNullOrEmpty(value)) {
throw new ArgumentException(ArgumentException.StandardMessage.NullOrEmpty, nameof(value));
} A non-nested enum would allow for an even more succinct usage: if (string.IsNullOrEmpty(value)) {
throw new ArgumentException(ArgumentExceptionMessage.NullOrEmpty, nameof(value));
} I realize there is a desire to avoid adding types to the root I wonder if there are any other "standard messages" worth considering for such an enum. |
I think it's reasonably verbose. It's close enough to retrieving a string from resources. I think we could add NullOrWhitespace to the enum. |
@justinvp, so Justin, do you think this is something we should submit for formal API review? |
@KrzysztofCwalina, Yes. I'll update the speclet above with your suggested design before the API review. |
/cc @terrajobst |
Looks reasonable to me. @weshaggard what are your thoughts? |
I think the proper solution, if this is intended to be implemented, is a class hierarchy:
This implies we need a refactoring of the Exception classes where exceptions such Alternatively, rather than breaking any classes or API's, instead of having
|
I don't think we should have hierarchies for exceptions that are usage errors and so should not be handled, but rather the calling code should be fixed. And argument exceptions are thrown in response to usage errors. Also the strings cannot be const as they are localized depending on current culture. |
I think it should be consistent. If we are not going to have different exceptions for usage errors, then we should remove ArgumentNullException, ArgumentOutOfRangeException, etc and replace them with ArgumentException. What is the reasoning (other than legacy) that differentiates them from the proposed ArgumentEmptyException and friends proposed here? |
We cannot remove these exceptions. Too massive of a breaking change. |
I'm not entirely sold on the value of this yet but if we do go as far as modifying ArgumentException itself I think I prefer Justin's other sample:
I like those methods better then adding the enum, it is more concise and essentially just as extensible as the enum. |
If you distil it down from the original proposal:
This means there are only two (2) new conditions being added:
Do these conditions provide valuable diagnostic information to developers and appear frequently enough to warrant first class exception support? With regard to [Edit] https://msdn.microsoft.com/en-us/library/system.invalidoperationexception%28v=vs.110%29.aspx |
That would certainly be preferable to adding an Throwing such an exception requires 3 or 4 calls today - one to allocate the exception, one to get the string, one to call the constructor and one to throw the exception. That's a lot of code considering that it is quite common for .NET methods to validate their arguments. If the methods are generic then you can end up with even more useless code if unshared generic instantiations are created due to value type arguments. For this reason the framework itself already uses methods like |
The value seems to be too low to justify the work. @stephentoub estimated that it might at best save us 150 lines of code in CoreFX, which should be a good proxy for this feature (libraries). It's not that the idea is bad, but the cost-benefit ratio doesn't seem to be worth it. |
Consider adding the ability to specify standard
ArgumentException
messages.Rationale
When validating
string
,Array
, andCollection
parameters, in addition to checking fornull
and throwingArgumentNullException
, it is often necessary to check for empty and throwArgumentException
.For example:
ArgumentNullException
already has a generic localized message built-in, so typically all you have to do is specify theparamName
:You get a localized
"Value cannot be null."
message from the framework for free.However,
ArgumentException
requires specifying a message when specifying aparamName
, so for the case of empty, you always have to specify your own"Value cannot be empty."
message:It's on you to localize the message if you care about globalization/localization.
For .NET Core itself, this means that each assembly that has such validation checks for empty must have it's own associated localizable resource for the message embedded inside the assembly.
These kinds of empty checks exist throughout .NET Core. You can get a rough sense with this search: https://github.com/dotnet/corefx/search?q=%22new+ArgumentException%22+empty&type=Code
These existing checks have customized message resources, but many could be replaced with a generic
"Value cannot be empty."
message without losing any information about the error (given that theparamName
is included with the message), allowing for the removal of many of the customized resources (if desired).Proposed API
Usage
Or simply:
Questions
Since
StandardMessage
includesNullOrEmpty
, shouldNull
be included as well? What aboutOutOfRange
?Any others?
Alternative Proposal
Add
ArgumentEmptyException
along the lines ofArgumentNullException
.Usage
Downsides to
ArgumentEmptyException
:System
namespace.ArgumentException
subclasses (e.g.ArgumentNullOrEmptyException
orArgumentNullOrWhiteSpaceException
).The text was updated successfully, but these errors were encountered: