Fun with Generic Enum Constraint
-
Ever tried to create a generic class which accepts
Enum
types only? Can be fun! I have a non-generic classEnumDescConverter
and wanted to add a generic versionEnumDescConverter<T>
. Easy, isn't it? Just writepublic class EnumDescConverter<T> : EnumDescConverter where T : Enum
and the error is
Constraint cannot be special class 'System.Enum'
Well, you have to use a different approach. An
Enum
is astruct
which implementsIConvertible
. Hence you can dopublic class EnumDescConverter : EnumDescConverter where T : struct, IConvertible
and then check in the constructor that
T
is really an enum:if (!enumType.IsEnum) { throw ...}
And now let's do more bad things. ;P The non-generic class has a functionpublic Enum GetEnumValue(string description)
Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:
public T GetEnumValue(string description)
And the warning is:
warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.
A possible solution, but not nice. If you make the method in the base class
virtual
, andoverride
it in the generic class, the error is:'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'
Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):
public T GetEnumValueT(string description)
{
return (T)GetEnumValue(description);
}And the next error arises:
Cannot convert type 'System.Enum' to 'T'
Of course,
return GetEnumValue(description) as T;
doesn't work either because an
Enum
is not aclass
:The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint
But the problem can be solved by a double-cast:
return (T)((object)GetEnumValue(description));
That's
Weird and Wonderful
, isn't it? :-D -
Ever tried to create a generic class which accepts
Enum
types only? Can be fun! I have a non-generic classEnumDescConverter
and wanted to add a generic versionEnumDescConverter<T>
. Easy, isn't it? Just writepublic class EnumDescConverter<T> : EnumDescConverter where T : Enum
and the error is
Constraint cannot be special class 'System.Enum'
Well, you have to use a different approach. An
Enum
is astruct
which implementsIConvertible
. Hence you can dopublic class EnumDescConverter : EnumDescConverter where T : struct, IConvertible
and then check in the constructor that
T
is really an enum:if (!enumType.IsEnum) { throw ...}
And now let's do more bad things. ;P The non-generic class has a functionpublic Enum GetEnumValue(string description)
Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:
public T GetEnumValue(string description)
And the warning is:
warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.
A possible solution, but not nice. If you make the method in the base class
virtual
, andoverride
it in the generic class, the error is:'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'
Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):
public T GetEnumValueT(string description)
{
return (T)GetEnumValue(description);
}And the next error arises:
Cannot convert type 'System.Enum' to 'T'
Of course,
return GetEnumValue(description) as T;
doesn't work either because an
Enum
is not aclass
:The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint
But the problem can be solved by a double-cast:
return (T)((object)GetEnumValue(description));
That's
Weird and Wonderful
, isn't it? :-D:omg: X|
If you have an important point to make, don't try to be subtle or clever. Use a pile driver. Hit the point once. Then come back and hit it again. Then hit it a third time - a tremendous whack. --Winston Churchill
-
Ever tried to create a generic class which accepts
Enum
types only? Can be fun! I have a non-generic classEnumDescConverter
and wanted to add a generic versionEnumDescConverter<T>
. Easy, isn't it? Just writepublic class EnumDescConverter<T> : EnumDescConverter where T : Enum
and the error is
Constraint cannot be special class 'System.Enum'
Well, you have to use a different approach. An
Enum
is astruct
which implementsIConvertible
. Hence you can dopublic class EnumDescConverter : EnumDescConverter where T : struct, IConvertible
and then check in the constructor that
T
is really an enum:if (!enumType.IsEnum) { throw ...}
And now let's do more bad things. ;P The non-generic class has a functionpublic Enum GetEnumValue(string description)
Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:
public T GetEnumValue(string description)
And the warning is:
warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.
A possible solution, but not nice. If you make the method in the base class
virtual
, andoverride
it in the generic class, the error is:'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'
Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):
public T GetEnumValueT(string description)
{
return (T)GetEnumValue(description);
}And the next error arises:
Cannot convert type 'System.Enum' to 'T'
Of course,
return GetEnumValue(description) as T;
doesn't work either because an
Enum
is not aclass
:The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint
But the problem can be solved by a double-cast:
return (T)((object)GetEnumValue(description));
That's
Weird and Wonderful
, isn't it? :-DA joke, I know, but that's just crazy! :laugh: :thumbsup:
You have just been Sharapova'd.
-
Ever tried to create a generic class which accepts
Enum
types only? Can be fun! I have a non-generic classEnumDescConverter
and wanted to add a generic versionEnumDescConverter<T>
. Easy, isn't it? Just writepublic class EnumDescConverter<T> : EnumDescConverter where T : Enum
and the error is
Constraint cannot be special class 'System.Enum'
Well, you have to use a different approach. An
Enum
is astruct
which implementsIConvertible
. Hence you can dopublic class EnumDescConverter : EnumDescConverter where T : struct, IConvertible
and then check in the constructor that
T
is really an enum:if (!enumType.IsEnum) { throw ...}
And now let's do more bad things. ;P The non-generic class has a functionpublic Enum GetEnumValue(string description)
Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:
public T GetEnumValue(string description)
And the warning is:
warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.
A possible solution, but not nice. If you make the method in the base class
virtual
, andoverride
it in the generic class, the error is:'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'
Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):
public T GetEnumValueT(string description)
{
return (T)GetEnumValue(description);
}And the next error arises:
Cannot convert type 'System.Enum' to 'T'
Of course,
return GetEnumValue(description) as T;
doesn't work either because an
Enum
is not aclass
:The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint
But the problem can be solved by a double-cast:
return (T)((object)GetEnumValue(description));
That's
Weird and Wonderful
, isn't it? :-DFody can do that[^] The fact that you need a third party IL manipulation library to do this is still a WTF though. Edit: damn autoincorrect.
What do you get when you cross a joke with a rhetorical question? The metaphorical solid rear-end expulsions have impacted the metaphorical motorized bladed rotating air movement mechanism. Do questions with multiple question marks annoy you???
-
Fody can do that[^] The fact that you need a third party IL manipulation library to do this is still a WTF though. Edit: damn autoincorrect.
What do you get when you cross a joke with a rhetorical question? The metaphorical solid rear-end expulsions have impacted the metaphorical motorized bladed rotating air movement mechanism. Do questions with multiple question marks annoy you???
Good find. Thanks.
-
Good find. Thanks.
Fody is very powerful. I don't use it, but I have a few places that it might be of help.
What do you get when you cross a joke with a rhetorical question? The metaphorical solid rear-end expulsions have impacted the metaphorical motorized bladed rotating air movement mechanism. Do questions with multiple question marks annoy you???
-
Ever tried to create a generic class which accepts
Enum
types only? Can be fun! I have a non-generic classEnumDescConverter
and wanted to add a generic versionEnumDescConverter<T>
. Easy, isn't it? Just writepublic class EnumDescConverter<T> : EnumDescConverter where T : Enum
and the error is
Constraint cannot be special class 'System.Enum'
Well, you have to use a different approach. An
Enum
is astruct
which implementsIConvertible
. Hence you can dopublic class EnumDescConverter : EnumDescConverter where T : struct, IConvertible
and then check in the constructor that
T
is really an enum:if (!enumType.IsEnum) { throw ...}
And now let's do more bad things. ;P The non-generic class has a functionpublic Enum GetEnumValue(string description)
Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:
public T GetEnumValue(string description)
And the warning is:
warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.
A possible solution, but not nice. If you make the method in the base class
virtual
, andoverride
it in the generic class, the error is:'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'
Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):
public T GetEnumValueT(string description)
{
return (T)GetEnumValue(description);
}And the next error arises:
Cannot convert type 'System.Enum' to 'T'
Of course,
return GetEnumValue(description) as T;
doesn't work either because an
Enum
is not aclass
:The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint
But the problem can be solved by a double-cast:
return (T)((object)GetEnumValue(description));
That's
Weird and Wonderful
, isn't it? :-DBut have you tried doing math with enum values in a generic class? :sigh: EnumOperators[^] Generic Math in C# Using Runtime Compilation[^]
-
But have you tried doing math with enum values in a generic class? :sigh: EnumOperators[^] Generic Math in C# Using Runtime Compilation[^]
Apart from combining / testing
Flags
values, when does it ever make sense to perform mathematical operations on Enum values?
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Apart from combining / testing
Flags
values, when does it ever make sense to perform mathematical operations on Enum values?
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Just wait until you need to.
-
Just wait until you need to.
If you ever need to then the much higher priority should be to refactor that bit of code so that you use something more appropriate. The actual value applied to an enumeration should never be relied upon to remain the same between versions of the code and so the result of any maths operation performed on it should be considered unreliable.
-
Ever tried to create a generic class which accepts
Enum
types only? Can be fun! I have a non-generic classEnumDescConverter
and wanted to add a generic versionEnumDescConverter<T>
. Easy, isn't it? Just writepublic class EnumDescConverter<T> : EnumDescConverter where T : Enum
and the error is
Constraint cannot be special class 'System.Enum'
Well, you have to use a different approach. An
Enum
is astruct
which implementsIConvertible
. Hence you can dopublic class EnumDescConverter : EnumDescConverter where T : struct, IConvertible
and then check in the constructor that
T
is really an enum:if (!enumType.IsEnum) { throw ...}
And now let's do more bad things. ;P The non-generic class has a functionpublic Enum GetEnumValue(string description)
Let's add a generic version in the generic class so that we do not need to cast the return value to the type of the enum in use:
public T GetEnumValue(string description)
And the warning is:
warning CS0108: 'EnumDescConverter.GetEnumValue(string)' hides inherited member 'EnumDescConverter.GetEnumValue(string)'. Use the new keyword if hiding was intended.
A possible solution, but not nice. If you make the method in the base class
virtual
, andoverride
it in the generic class, the error is:'EnumDescConverter.GetEnumValue(string)': return type must be 'System.Enum' to match overridden member 'EnumDescConverter.GetEnumValue(string)'
Hm. Let me change the name of the function, and in its body just call the base class' method and cast the return value (not a nice solution either):
public T GetEnumValueT(string description)
{
return (T)GetEnumValue(description);
}And the next error arises:
Cannot convert type 'System.Enum' to 'T'
Of course,
return GetEnumValue(description) as T;
doesn't work either because an
Enum
is not aclass
:The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint
But the problem can be solved by a double-cast:
return (T)((object)GetEnumValue(description));
That's
Weird and Wonderful
, isn't it? :-DIn your last method, beside being awkward, you are boxing & unboxing the value. Which probably increase the time that method takes to run by at least one order of magnitude. A way to avoid this is to take advantage of something we already know... enums are `IConvertible`. void Main() { var b = new EnumDescConverter(); b.GetEnumValueT("Dummy desc").Dump(); } enum nums {zero, one, two, three}; enum Nums {Zero, One, Two, Three}; class EnumDescConverter { /// Simplified a bit for example. protected IConvertible GetEnumValue(string description) {return nums.one; } } class EnumDescConverter : EnumDescConverter where T : struct, IConvertible { public T GetEnumValueT(string description) { return (T) GetEnumValue(description);} } P.S. http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2557231-enums-constraint-for-generics[^]
Truth, James