I have an enum like this:
public enum MyEnum
{
Character = 'C',
Number = 'N',
}
Then I'm doing something like this:
char myChar = 'C';
var value = Enum.GetName(typeof(MyEnum), myChar); //throw exception on .NET 3.5 or less
This code is OK in projects with .NET 4 but throws exception on .NET 3.5 or less. This is the exception:
The value passed in must be an enum base or an underlying type for an enum, such as an Int32.Parameter name: value
So I published my project with .NET 4 and share it with my friends and told them they need .NET4. They run the program successfully but find out the program throws the same exception on some systems even with .NET 4! Anyone knows what is the cause of this exception?
I solved the problem this way, but interested to know why it was working on some systems and not working on some others? (all of them has .NET4)
var value = Enum.GetName(typeof(MyEnum), (int)myChar);
This was changed in .NET 4.5. Beware that it is difficult to see whether you have 4.0 or 4.5 installed on the machine, 4.5 replaces 4.0 and uses the same install directory as 4.0.
The method that was changed is the one that @Dirk quoted, the internal IsIntegerType() helper method. The 4.0 version looks like this:
internal static bool IsIntegerType(Type t)
{
if (((!(t == typeof(int)) && !(t == typeof(short))) && (!(t == typeof(ushort)) &&
!(t == typeof(byte)))) && ((!(t == typeof(sbyte)) && !(t == typeof(uint))) &&
!(t == typeof(long))))
{
return (t == typeof(ulong));
}
return true;
}
Note how typeof(char) isn't being tested so it doesn't consider it a valid type for the value argument you pass to Enum.GetName().
These kind of changes in a .NET Framework version that is not a side-by-side version are fairly uncool, it does make it awfully hard to diagnose program failure. Especially since you targeted NET 4.0 in your project but ended up running on a machine that had 4.5 installed so never noticed the problem. But kaboom on a machine on which only 4.0 is installed.
The best possible spin to put on it that this was a bug in 4.0 that they fixed in 4.5. And frankly it was, you of course expected a char to be completely valid since that's what you used to initialize the enum members. It does show how difficult it is for Microsoft to ever fix bugs.
The implementation for Enum.GetName
changed from 2.0 to 4.0.
This is the decompiled version from 2.0 (with ILSpy):
public static string GetName(Type enumType, object value)
{
[...]
// Enum.intType = typeof(int)
Type type = value.GetType();
if (type.IsEnum || type == Enum.intType || type == typeof(short) || type == typeof(ushort) || type == typeof(byte) || type == typeof(sbyte) || type == typeof(uint) || type == typeof(long) || type == typeof(ulong))
{
return Enum.InternalGetValueAsString(enumType, value);
}
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
}
You can see that for type = typeof(char)
this exception is throw.
And for 4.0 it is:
public static string GetName(Type enumType, object value)
{
[...]
// this is actually in a method called by GetName, I put it here for clarity
Type type = value.GetType();
if (!type.IsEnum && !Type.IsIntegerType(type))
{
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
}
[...]
}
// Type.IsIntegerType
internal static bool IsIntegerType(Type t)
{
return t == typeof(int) || t == typeof(short) || t == typeof(ushort) || t == typeof(byte) || t == typeof(sbyte) || t == typeof(uint) || t == typeof(long) || t == typeof(ulong) || t == typeof(char) || t == typeof(bool);
}
But here type = typeof(char)
doesn't result in the exception.
The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong
MSDN.
You can't create Enum char value, .NET lets you do this, but compilator converts your char values to its equivalent int representation (ASCII).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With