I am curious how would you maintain your code once you throw a System.ComponentModel.InvalidEnumArgumentException.
Basically I have a switch statement like this:
switch (enumValue)
{
case MyEnum.Value1:
break;
case MyEnum.Value2:
break;
default:
throw new InvalidEnumArgumentException();
}
What if I decide to add more values to MyEnum in the future, for example, Value3 and Value4? That would mean I would end up throwing a misleading exception. How would I prevent this?
Should I use reflection before throwing? What exception should I throw in this case? I'm looking for suggestions.
I just discovered this exception a couple minutes ago so maybe I am looking at this in the wrong context. Is this exception thrown when a certain enum argument is not supported (in which case Value3 and Value4 would not be supported)?
The problem you state depends on the context, if a method receives an enumeration as an argument it must specify what values does it support and what it does with an unknown enumeration value.
If you add more enumeration options you need to decide what to do even if you were not throwing an exception in the default case.
Be reminded that the exception is special helpful since you can pass any integer as an enumeration value.
For example:
enum Foo { A, B }
static int Bar(Foo f)
{
switch (f)
{
case Foo.A:
return 1;
case Foo.B:
return 2;
default:
throw new InvalidEnumArgumentException("f", (int)f, typeof(Foo));
}
}
static void Main()
{
Bar(Foo.A);
Bar((Foo)99);
}
What if I decide to add more values to MyEnum in the future, for example, Value3 and Value4?
That would mean I would end up throwing a misleading exception. How would I prevent this?
When you're using InvalidEnumArgumentException the key thing to understand is argument. By throwing the exception you are saying that the argument for the method was invalid. (InvalidEnumArgumentException derives from ArgumentException.) It doesn't necessarily mean that the value was not a member of the enum. So I would not consider it misleading.
I wouldn't be using that exception you're using in that context. By virtue of enumValue being of type MyEnum (I presume?) it can never contain an invalid enum value. If you have switches based on the value of the enum which need to fail if they don't recognise the value then you'll need to throw an appropriate exception (maybe just a normal ArgumentException?) but in most cases I guess you'd let the code run do nothing for an unknown enum value.
You are using the exception in a wrong way:
http://msdn.microsoft.com/en-us/library/system.componentmodel.invalidenumargumentexception.aspx
This exception is thrown if you pass an invalid enumeration value to a method or when setting a property.
I believe you are looking it in the wrong context, if these weren't enum but some specific values which were based on some business rule, so in such cases as the rules increase you would touch up relevant codes like these to incorporate the new ones. So if you are modifying the Enum then you should be look around for changes like these.
To validate the incoming enumeration value use the following static method...
public void MyMethod(MyEnum e)
{
if (!Enum.IsDefined(typeof(MyEnum), e))
throw new InvalidEnumArgumentException("e", (int)e, typeof(MyEnum));
...and you do not need to alter the check if new enum values are added in the future.
Related
I have the following enumerator:
enum Foo { Bar, Baz };
In the following code, the compiler aborts with the error:
use of unassigned local variable 'str'
The code:
string str;
Foo foo = Foo.Bar;
switch (foo)
{
case Foo.Bar: str = "a"; break;
case Foo.Baz: str = "b"; break;
}
str.ToLower();
The switch covers all the possible values of the enumerator. But the compiler still thinks that str might be unassigned. Why is that? Of course I could put a default case in there, but that would be wrong, since errors are not caught at compile-time. For example, if the Foo enum is modified later on and a new value added, then it would be nice to get a compiler error. If I use a default case, then the error is not caught when recompiling.
I suppose there is no way to get the compiler to accept a switch without a default case and raise an error if Foo is extended later on?
I suppose there is no way to get the compiler to accept a switch without a default case and raise an error if Foo is extended later on?
This is correct. Long story short, the reason why the compiler does this is that it is possible to assign foo a value that is not one of a valid enum Foos values by typecasting an int, making it possible to bypass all cases of the switch.
The solution that I use in situations like this is to add an assertion:
switch (foo)
{
case Foo.Bar: str = "a"; break;
case Foo.Baz: str = "b"; break;
default: Debug.Assert(false, "An enum value is not covered by switch: "+foo);
}
Enums are statically typed and type checked. But the checking does not extend to ensure that enum values only assume defined values. In fact, for Flags enums variables often do not assume any single defined value.
Like that:
Foo f = (Foo)1234; //valid
And that's why the switch can pick the default case at runtime and str could end up being used in an uninitialized state.
Some languages have stronger constructs than .NET enums such as Haskell and F#.
The enum is essentially an int and any int value could be assigned to it. This usually doesn't happen but is why you need to handle the default case or simply declare the string with a default value (like null)
Of course I could put a default case in there, but that would be wrong
That would be according to good practices. Your enum can still contain other numeric values, because enums in C# are only compile time layer above the underlying numeric representation - think const fields. Foo f = (Foo)int.MaxValue; will still compile and run, but now you don't have a switch case for it.
Depending on your interface, you may either put a default case with an exception there, define str with null, or an empty string.
your best bet is to just initialize str with an empty string in your first line. the compiler can't (or won't) try to analyse the switch logic that deeply.
I am implementing an IDictionary interface, which has parameter object for its get set.
object this [object key] { get; set; }
I want to enforce the key to be type of string, so in my code I do:
(if key.GetType() != typeof(string)) {
//
}
I want to throw an exception when this happen. However I don't know what the most appropriate exception to use in this case. The closest one I can find is TypeInitializationException and ArgumentException. However, it is stated in this document: "Do throw System.ArgumentException or one of its subtypes if bad arguments are passed to a member", which makes me wonder if mine is the right use case for it.
What should I use my case? Should I use Assert instead of throwing Exception?
ArgumentException is the correct exception. The entire BCL uses it and so should you. TypeInitializationException does not fit at all. It has one use case only: a throwing static ctor.
That said, if you are not producing a library (just internal code) you can deviate from that convention if there is a good reason. If you want to use a Debug.Assert or some alternative, feel free to do it.
First I think, the best solution is Mathhew's; Why you just not using the Generic dictionary of type string.
If you need to apply the other approach than Code Contracts is the best way to do that.
Example:
Contract.Requires(key is string);
etc.
Assert is not suitable for this problem but ArgumentException can be applied.
Thanks
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.
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.
I'd throw the InvalidEnumArgumentException as it will give more detailed information in this case, you are checking on an enum
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());
InvalidArgumentException.
when user pass some invalid value or null value when value value is required, it is recommended to handle InvalidArgumentException .
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);
I know I can just typecast the result from GetHttpCode() to HttpStatusCode, but I don't like to typecast enums. Especially because the MSDN doc doesn't explicitely say that the values of the enums are always the exact corresponding http status code.
I feel that GetHttpCode() should just return HttpStatusCode.
Should I just stop complaining and typecast?
catch(HttpException ex)
{
switch((HttpStatusCode)ex.GetHttpCode())
{
case HttpStatusCode.NotFound:
// Do stuff...
break;
// More cases...
}
}
EDIT: note that HttpWebResponse.StatusCode is of type HttpStatusCode
It's worth noting that HTTP permits custom status codes, so it's not guaranteed that the enum will contain the value from your response. For this reason, it's sensible for the API to return the int value instead of trying to use the enum.
HTTP status codes don't have to come from a fixed list, though they usually do. Using an enum is a convenience. Requiring an enum would be wrong.
A response contains an integer value for the error code. The int is the actual error code. The enumeration allows for a 'friendly' representation of the error code.
Should I just stop complaining and typecast?
Yes. Or work with the corresponding integer values.
Yes, you should do it like that. Most of all, since the code you yourself provided shields you from working with any integer values or status numbers all together. So technically, it does not matter, whether the enum-values correspont to the status numbers.
Suppose we have a method that accepts a value of an enumeration. After this method checks that the value is valid, it switches over the possible values. So the question is, what is the preferred method of handling unexpected values after the value range has been validated?
For example:
enum Mood { Happy, Sad }
public void PrintMood(Mood mood)
{
if (!Enum.IsDefined(typeof(Mood), mood))
{
throw new ArgumentOutOfRangeException("mood");
}
switch (mood)
{
case Happy: Console.WriteLine("I am happy"); break;
case Sad: Console.WriteLine("I am sad"); break;
default: // what should we do here?
}
What is the preferred method of handling the default case?
Leave a comment like // can never happen
Debug.Fail() (or Debug.Assert(false))
throw new NotImplementedException() (or any other exception)
Some other way I haven't thought of
I guess most of the above answers are valid, but I'm not sure any are correct.
The correct answer is, you very rarely switch in an OO language, it indicates you are doing your OO wrong. In this case, it's a perfect indication that your Enum class has problems.
You should just be calling Console.WriteLine(mood.moodMessage()), and defining moodMessage for each of the states.
If a new state is added--All Your Code Should Adapt Automatically, nothing should fail, throw an exception or need changes.
Edit: response to comment.
In your example, to be "Good OO" the functionality of the file mode would be controlled by the FileMode object. It could contain a delegate object with "open, read, write..." operations that are different for each FileMode, so File.open("name", FileMode.Create) could be implemented as (sorry about the lack of familiarity with the API):
open(String name, FileMode mode) {
// May throw an exception if, for instance, mode is Open and file doesn't exist
// May also create the file depending on Mode
FileHandle fh = mode.getHandle(name);
... code to actually open fh here...
// Let Truncate and append do their special handling
mode.setPosition(fh);
}
This is much neater than trying to do it with switches... (by the way, the methods would be both package-private and possibly delegated to "Mode" classes)
When OO is done well, every single method looks like a few lines of really understandable, simple code--TOO simple. You always get the feeling that there is some big messy "Cheese Nucleus" holding together all the little nacho objects, but you can't ever find it--it's nachos all the way down...
I prefer to throw new NotImplementedException("Unhandled Mood: " + mood). The point is that the enumeration may change in the future, and this method may not be updated accordingly. Throwing an exception seems to be the safest method.
I don't like the Debug.Fail() method, because the method may be part of a library, and the new values might not be tested in debug mode. Other applications using that library can face weird runtime behaviour in that case, while in the case of throwing an exception the error will be known immediately.
Note: NotImplementedException exists in commons.lang.
In Java, the standard way is to throw an AssertionError, for two reasons:
This ensures that even if asserts are disabled, an error is thrown.
You're asserting that there are no other enum values, so AssertionError documents your assumptions better than NotImplementedException (which Java doesn't have anyway).
My opinion is that since it is a programmer error you should either assert on it or throw a RuntimException (Java, or whatever the equivalent is for other languages). I have my own UnhandledEnumException that extends from RuntimeException that I use for this.
The correct program response would be to die in a manner that will allow the developer to easily spot the problem. mmyers and JaredPar both gave good ways to do that.
Why die? That seems so extreme!
The reason being that if you're not handling an enum value properly and just fall through, you're putting your program into an unexpected state. Once you're in an unexpected state, who knows what's going on. This can lead to bad data, errors that are harder to track down, or even security vulnerabilities.
Also, if the program dies, there's a much greater chance that you're going to catch it in QA and thus it doesn't even go out the door.
For pretty much every switch statement in my code base, I have the following default case
switch( value ) {
...
default:
Contract.InvalidEnumValue(value);
}
The method will throw an exception detailing the value of the enum at the point an error was detected.
public static void InvalidEnumValue<T>(T value) where T: struct
{
ThrowIfFalse(typeof(T).IsEnum, "Expected an enum type");
Violation("Invalid Enum value of Type {0} : {1}", new object[] { typeof(T).Name, value });
}
For C#, something worth knowing is that Enum.IsDefined() is dangerous. You can't rely on it like you are. Getting something not of the expected values is a good case for throwing an exception and dying loudly.
In Java, it's different because enums are classes not integers so you really can't get unexpected values (unless the enum is updated and your switch statement isn't), which is one big reason why I much prefer Java enums. You also have to cater for null values. But getting a non-null case you don't recognize is a good case for throwing an exception too.
You could have a trace for the default calling out the value of the passed enum. Throwing exceptions is OK but in a large application there will be several places where your code does not care about other values of the enum.
So, unless you are sure that the code intends to handle all possible values of the enum, you'll have to go back later and remove the exception.
This is one of those questions that proves why test driven development is so important.
In this case I'd go for a NotSupportedException because literally the value was unhandled and therefore not supported. A NotImplementedException gives more the idea of: "This is not finished yet" ;)
The calling code should be able to handle a situation like this and unit tests can be created to easily test these kind of situations.
Call it an opinion or a preference, but the idea behind the enum is that it represents the full list of possible values. If an "unexpected value" is being passed around in code, then the enum (or purpose behind the enum) is not up to date. My personal preference is that every enum carry a default assignment of Undefined. Given that the enum is a defined list, it should never be out-of-date with your consuming code.
As far as what to do if your function is getting either an unexpected value or Undefined in my case, a generic answer doesn't seem possible. For me, it depends on the context of the reason for evaluating the enum value: is it a situation where code execution should halt, or can a default value be used?
It is the responsibility of the calling function to provide valid input and implicitely anything not in the enum is invalid (Pragmatic programmer seems to imply this). That said, this implies that any time you change your enum, you must change ALL code that accepts it as input (and SOME code that yields it as output). But that is probably true anyways. If you have an enum that changes often, you probably should be using something other than an enum, considering that enums are normally compile-time entities.
I usually try to define undefined value (0):
enum Mood { Undefined = 0, Happy, Sad }
That way I can always say:
switch (mood)
{
case Happy: Console.WriteLine("I am happy"); break;
case Sad: Console.WriteLine("I am sad"); break;
case Undefined: // handle undefined case
default: // at this point it is obvious that there is an unknown problem
// -> throw -> die :-)
}
This is at least how I usually do this.