Skip to content

[API Proposal]: ArgumentException.ThrowIfNullOrEmpty(string) #62628

Closed

Description

@datvm

Background and motivation

Inspired by ArgumentNullException.ThrowIfNull(object). string.IsNullOrEmpty(text) is a frequent check especially in web/Console project. At first I thought InvalidDataException would be the best name but it is in System.IO namespace, so I think the closest should be ArgumentException so user doesn't need to import that namespace.

Now:

if (string.IsNullOrEmpty(input)) { throw new ArgumentException($"{nameof(input)} must contain value."); }

If the API is approved:

ArgumentException.ThrowIfNullOrEmpty(input);

While we are at it, personally I rarely use it but maybe ThrowIfNullOrWhiteSpace may be useful for others as well?

API Proposal

namespace System
{
    public class ArgumentException : SystemException
    {
        public static void ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression("argument")] string? paramName = null)
    }
}

API Usage

ArgumentException.ThrowIfNullOrEmpty(input);

Alternative Designs

No response

Risks

No response

Activity

  1. added
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    on Dec 10, 2021
  2. ghost added
    untriagedNew issue has not been triaged by the area owner
    on Dec 10, 2021
  3. Clockwork-Muse commented on Dec 10, 2021

    @Clockwork-Muse
    Contributor

    [NotNull]

    ... but the parameter can be null, since that's the point of the exception?

  4. stephentoub commented on Dec 10, 2021

    @stephentoub
    Member

    The argument to the existing ThrowIfNull is declared as:

    [NotNull] object? argument

    which uses ? to avoid warnings when being used with something that may be null, but then [NotNull] to say "upon successful return from this method, it's guaranteed argument isn't null."

  5. added
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    and removed
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    on Dec 14, 2021
  6. danmoseley commented on Dec 14, 2021

    @danmoseley
    Contributor

    Makes sense to me. It would collapse stuff like

    if (name == null)
    {
    throw new ArgumentNullException(nameof(name));
    }
    if (name.Length == 0)
    {
    throw new ArgumentException(SR.Argument_EmptyName, nameof(name));
    }

    from 10 lines to 1.

    In that example, it has a custom message, ie "Empty name is not legal.", and using this proposed API would change that to something generic. I think that's totally fine. There are cases where perhaps the message adds slightly more value eg "Empty file name is not legal." and perhaps those would not change to use this API, which is fine.

  7. hrrrrustic commented on Dec 15, 2021

    @hrrrrustic
    Contributor

    Maybe it would also make sense to add overload with IReadOnlyCollection<T> or simply ICollection<T>?

    public static void ThrowIfNullOrEmpty<T>([NotNull] I/*ReadOnly*/Collection<T> argument, [CallerArgumentExpression("argument")] string? paramName = null);

    Usages:

    if (source == null || source.Length == 0)
    throw new ArgumentException(SR.Format(SR.MissingParameter, nameof(source)));

    if (rawData == null || rawData.Length == 0)
    throw new ArgumentException(SR.Arg_EmptyOrNullArray, nameof(rawData));

    Didn't try to find splitted if-checks

    Makes sense to me. It would collapse stuff like

    if (name == null)
    {
    throw new ArgumentNullException(nameof(name));
    }
    if (name.Length == 0)
    {
    throw new ArgumentException(SR.Argument_EmptyName, nameof(name));
    }

    from 10 lines to 1.

    In that example, it has a custom message, ie "Empty name is not legal.", and using this proposed API would change that to something generic. I think that's totally fine. There are cases where perhaps the message adds slightly more value eg "Empty file name is not legal." and perhaps those would not change to use this API, which is fine.

  8. Rubenisme commented on Dec 23, 2021

    @Rubenisme

    If this is done, then after that I'm sure someone will ask: "What about an ArgumentException.ThrowIfNullOrWhiteSpace?".
    I think the string.IsNullOrWhiteSpace method gets used a lot less than the string.IsNullOrEmpty method, so might not be as useful.

  9. terrajobst commented on Jan 4, 2022

    @terrajobst
    Contributor

    Video

    • Looks good as proposed
      • Might be good to do a pass what ArgumentOutOfRangeException cases we use internally. We could base it off the unique resource strings we use in corlib.
    • The API should
      • Throw ArgumentNullException if argument is null, otherwise ArgumentException
    • We don't believe we need an overload of ThrowIfNullOrEmpty for collections as this feels rare.
    namespace System
    {
        public partial class ArgumentException
        {
            public static void ThrowIfNullOrEmpty([NotNull] string? argument,
                                                  [CallerArgumentExpression("argument")] string? paramName = null);
        }
    }
  10. added
    api-approvedAPI was approved in API review, it can be implemented
    and removed
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    on Jan 4, 2022
  11. 8 remaining items

  12. deeprobin commented on Jan 11, 2022

    @deeprobin
    Contributor

    Makes sense to me. It would collapse stuff like

    if (name == null)
    {
    throw new ArgumentNullException(nameof(name));
    }
    if (name.Length == 0)
    {
    throw new ArgumentException(SR.Argument_EmptyName, nameof(name));
    }

    from 10 lines to 1.

    In that example, it has a custom message, ie "Empty name is not legal.", and using this proposed API would change that to something generic. I think that's totally fine. There are cases where perhaps the message adds slightly more value eg "Empty file name is not legal." and perhaps those would not change to use this API, which is fine.

    But that would change the exception behavior, since an ArgumentException would be thrown instead of an ArgumentNullException?

    Or should the proposal throw an ArgumentNullException? In that case it would make sense to move it to the ArgumentNullException class?

  13. deeprobin commented on Jan 11, 2022

    @deeprobin
    Contributor

    add this case anyway for completeness.

    I wonder what's the API designer team philosophy on this. From the video I watched, it seems they prefer to have only very needed APIs added instead of "completeness". I understand and agree with this approach since .NET now can be used in Web environment through WebAssembly as well so they probably want the standard library to be as small as possible. You should check the above video, they discussed about the possibilities of adding other throw helpers as well.

    You're right about that.
    For NativeAOT we could consider that isn't it? Or are unused methods not optimized away?

  14. danmoseley commented on Jan 11, 2022

    @danmoseley
    Contributor

    Or should the proposal throw an ArgumentNullException? In that case it would make sense to move it to the ArgumentNullException class?

    As noted above, it should throw ANE (which is-a AE) if the argument is null.

  15. danmoseley commented on Jan 11, 2022

    @danmoseley
    Contributor

    @danmoseley awesome, please go ahead

    @datvm I meant, are you interested in making the PR? No obligation, it's just that you opened the issue so asking you first. If anyone else is interested, they're welcome too.

    We have full instructions for how to contribute and can help as much as you need.

  16. datvm commented on Jan 11, 2022

    @datvm
    Author

    @danmoseley ah thanks for clarifying. I will leave this one for someone else. I will try next time when I have studied an example pull request.

  17. danmoseley commented on Jan 11, 2022

    @danmoseley
    Contributor

    @datvm sounds good, if you are interested there are issues with the 'easy' label and perhaps there's one you might be interested to start with.

    Anyone else interested in offering a PR here?

  18. deeprobin commented on Jan 12, 2022

    @deeprobin
    Contributor

    @datvm sounds good, if you are interested there are issues with the 'easy' label and perhaps there's one you might be interested to start with.

    Anyone else interested in offering a PR here?

    Doesn't seem like a big deal. If it's nothing urgent, I'm happy to do it.

  19. self-assigned this
    on Jan 25, 2022
  20. ghost added
    in-prThere is an active PR which will close this issue when it is merged
    on Jan 26, 2022
  21. stephentoub commented on Jan 27, 2022

    @stephentoub
    Member
  22. removed
    untriagedNew issue has not been triaged by the area owner
    on Jan 27, 2022
  23. added this to the 7.0.0 milestone on Jan 27, 2022
  24. ghost removed
    in-prThere is an active PR which will close this issue when it is merged
    on Jan 28, 2022
  25. ghost locked as resolved and limited conversation to collaborators on Feb 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions