19

NOTE: This is different than the proposed duplicates as this deals with an argument rather than a value. The behavior and applicable scenarios are essentially different.

Say we have SomeEnum and have a switch statement handling it like:

enum SomeEnum
{
    One,
    Two,
}

void someFunc(SomeEnum value)
{
    switch(value)
    {
        case SomeEnum.One:
            ...
            break;
        case SomeEnum.Two:
            ... 
            break;
        default:
            throw new ??????Exception("Unhandled value: " + value.ToString());    
    }
}

As you see we handle all possible enum values but still keep a default throwing an exception in case a new member gets added and we want to make sure we are aware of the missing handling.

My question is: what's the right exception in such circumstances where you want to notify that the given code path is not handled/implemented or should have never been visited? We used to use NotImplementedException but it doesn't seem to be the right fit. Our next candidate is InvalidOperationException but the term doesn't sound right. What's the right one and why?

EDIT: C# 8.0 introduced switch expressions which produce compiler warnings for non-exahustive switch statements. That's another reason why you should use switch expressions over switch statements whenever applicable. The same function can be written in a safer way like:

void someFunc(SomeEnum value)
{
    _ = value switch
    {
        SomeEnum.One => ....,
        SomeEnum.Two => ...., 
    }
}

When a new member gets added to SomeEnum, the compiler will show the warning "CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'EnumHandling.SomeEnum.Three' is not covered." for the switch expression which makes it way easier to catch potential bugs.

Sedat Kapanoglu
  • 46,641
  • 25
  • 114
  • 148
  • 1
    to those who closed this as a duplicate: the question you pointed at 1) is a different case (unhandled return value not argument, which I have a separate question for) 2) has the wrong answer regarding return values. you are actually harming who come here by denouncing the answers given here and directing them to the wrong context and answers. – Sedat Kapanoglu Apr 01 '16 at 23:48
  • 1
    @Habib and other close-voters: How is this a duplicate? This question is specific to an `enum` value that is passed in as an argument. The other question is about the general case of unsupported switch cases. Both questions have different answers with a different reasoning. – O. R. Mapper Sep 29 '17 at 14:48

5 Answers5

23

ArgumentException looks the most correct to me in this instance (though is not defined in the BCL).

There is a specialized exception for enum arguments - InvalidEnumArgumentException:

The exception thrown when using invalid arguments that are enumerators.

An alternative is ArgumentOutOfRangeException:

The exception that is thrown when the value of an argument is outside the allowable range of values as defined by the invoked method.

The logic for using these is that the passed in argument (value) is not valid as far as someFunc is concerned.

Troy Poulter
  • 677
  • 1
  • 8
  • 29
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • 2
    You mean [`ArgumentException`](http://msdn.microsoft.com/en-us/library/system.argumentexception.aspx)? [`InvalidArgumentException`](http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.common.invalidargumentexception.aspx) is for Sql-Server. – Tim Schmelter Nov 30 '12 at 12:00
  • 2
    InvalidArgumentException is in the Microsoft.SqlServer.Management.Common namespace and hardly appropriate for the general case - especially since it derives from ConnectionException – Joe Nov 30 '12 at 12:02
  • Why not `InvalidEnumArgumentException`? – O. R. Mapper Nov 30 '12 at 12:02
  • @TimSchmelter - No. Several other libraries do define `InvalidArgumentException` (which semantically may be the most correct here). For instance SMO defines it, MS Office libraries also define it. – Oded Nov 30 '12 at 12:02
  • @O.R.Mapper - Good one. Didn't think of that one... thanks. – Oded Nov 30 '12 at 12:03
  • @Oded: Someone else thought of it first - see the respective answer below. – O. R. Mapper Nov 30 '12 at 12:04
  • 1
    "There is a specialized version for enums - InvalidEnumArgumentException:" - InvalidEnumArgumentException is not a specialized version of (derived from) InvalidArgumentException. – Joe Nov 30 '12 at 12:09
  • This is ok for parameter validation but is it the right exception when it's not a parameter but a return value from another function call? I'll edit question to broaden it's scope. – Sedat Kapanoglu Nov 30 '12 at 12:13
  • 1
    @ssg: I think you should ask another question for that, because IMO it has another answer. – O. R. Mapper Nov 30 '12 at 12:14
  • @O.R.Mapper: I didn't think two cases would have two different answers. Should I revert my edit and create a new one? – Sedat Kapanoglu Nov 30 '12 at 12:16
  • 1
    @ssg: With respect to future readers and general SO guidelines, I'd be in favour of that: My answer to your first question (argument) would definitely be `InvalidEnumArgumentException`, whereas my answer to the other question (internal value) would definitely be `InvalidOperationException`. – O. R. Mapper Nov 30 '12 at 12:17
  • 1
    @ssg - It would definitely have a different answer. – Oded Nov 30 '12 at 12:17
  • 1
    @ssg: The point/reason being that with an argument, the one who is first confronted with the exception (the calling code) did something wrong (pass an invalid argument value), whereas with an internal return value, the calling code is seldom guilty of the problem and can at most try to deal with the situation gracefully, but not prevent the problem. – O. R. Mapper Nov 30 '12 at 12:21
  • @O.R.Mapper: it makes sense, asked the other question. – Sedat Kapanoglu Nov 30 '12 at 12:22
16

I'd throw the InvalidEnumArgumentException as it will give more detailed information in this case, you are checking on an enum

O. R. Mapper
  • 20,083
  • 9
  • 69
  • 114
CR41G14
  • 5,464
  • 5
  • 43
  • 64
  • 1
    As the difference might easily be overread, I'd exceptionally like to point out how this answer is probably a better solution than the other answers that point to the (more generic, less specific) `ArgumentException`. – O. R. Mapper Nov 30 '12 at 12:01
  • 1
    @O.R.Mapper Thanks I agree, the more specific you can be the more detailed information you can derive from the exception – CR41G14 Nov 30 '12 at 12:12
  • @O.R.Mapper I agree but the question was closed. Since now it's open again, I picked this as the accepted answer. Thanks @CR41G14! – Sedat Kapanoglu Mar 16 '20 at 21:27
4

Since you have the login in a function you can throw InvalidArgumentException.

The exception that is raised when a parameter that is not valid is passed to a method on the referenced connection to the server.

EDIT: A better alternative would be: ArgumentException, since InvalidArgumentException in Microsoft.SqlServer.Management.Common namespace. Something like:

throw new ArgumentException("Unhandled value: " + value.ToString());
Habib
  • 219,104
  • 29
  • 407
  • 436
  • 2
    InvalidArgumentException is in the Microsoft.SqlServer.Management.Common namespace and hardly appropriate for the general case - especially since it derives from ConnectionException – Joe Nov 30 '12 at 12:05
  • @Joe, thanks for that, I was editing my answer after seeing your comment earlier – Habib Nov 30 '12 at 12:06
0

InvalidArgumentException. when user pass some invalid value or null value when value value is required, it is recommended to handle InvalidArgumentException .

Manibhadra
  • 400
  • 4
  • 6
0

If you were using Code Contracts (something I HIGHLY recommend), you would put this at the start of the method:

Contract.Requires(value == SomeEnum.One || value == SomeEnum.Two);

If you want to check a range of an enum which has too many individual values to write them all explicitly, you can do it like this:

Contract.Requires(SomeEnum.One <= value && value <= SomeEnum.Two);
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276