Related
Because Enums aren't guaranteed to be of type int...
public enum ExampleEnum : int / ulong / whatever
You cannot do this with enums:
int i = (int)exampleEnum;
However in my case, while I don't know the exact 'type of enum' being used, I can guarantee that it will be a "int type" of enum.
So I can do this:
int i = Convert.ToInt32(exampleEnum);
Cool. Here's the problem: I don't know of a way to do the inverse (which I need to do), as:
Enum exampleEnum = (Enum)exampleEnum;
has error:
Cannot cast expression of type 'int' to type 'Enum'
And I cannot find an inverse of Convert.ToInt32(Enum enum)
That is the question, if you think more detail on what I'm trying to do is useful, I can provide you with it. But in a nutshell I am creating a generic GUI method that takes in any type of Enum:
public static int EditorPrefEnumField(string label, Enum defaultValue, string editorPrefString)
and getting it to work (the way I want) involves converting the Enum to and from an int.
You can use Enum.ToObject() method. You need to specify the actual enum type for that. Here is a generic method to encapsulate Enum.ToObject()
public enum TestEnum : int
{
A=1, B=2, C=3
};
public T GetEnumFromInt<T>(int value) where T : Enum
{
return (T)Enum.ToObject(typeof(T), value);
}
private void button1_Click(object sender, EventArgs e)
{
Enum value = GetEnumFromInt<TestEnum>(2);
MessageBox.Show(value.ToString()); // Displays "B"
}
You need to specify the concrete type of Enum you want because Enum is an abstract type and one cannot create instances of abstract types.
Take this code where I store an error code as an Int:
public class CommonError
{
public int Code { get; set; }
public CommonError FromErrorCode(Enum code, string description = "")
{
Code = (int)Enum.Parse(code.GetType(), code.ToString());
return this;
}
}
Yet what I'm doing when I call it is parsing in different Enums:
new CommonError().FromErrorCode((int)GeneralErrorCodes.SYSTEM_BASE_ERROR);
Cool. Here's the problem: I don't know of a way to do the inverse (which I need to do)
To do the reverse of this you need the Enum Type, eg:
Enum.GetNames(typeof(AnEmumType))
Enum.GetValues(typeof(AnEmumType)).ToList();
If I have the following enum:
public enum ReturnValue{
Success = 0,
FailReason1 = 1,
FailReason2 = 2
//Etc...
}
Can I avoid casting when I return, like this:
public static int main(string[] args){
return (int)ReturnValue.Success;
}
If not, why isn't an enum value treated as an int by default?
enums are supposed to be type safe. I think they didn't make them implicitly castable to discourage other uses. Although the framework allows you to assign a constant value to them, you should reconsider your intent. If you primarily use the enum for storing constant values, consider using a static class:
public static class ReturnValue
{
public const int Success = 0;
public const int FailReason1 = 1;
public const int FailReason2 = 2;
//Etc...
}
That lets you do this.
public static int main(string[] args){
return ReturnValue.Success;
}
EDIT
When you do want to provide values to an enum is when you want to combine them. See the below example:
[Flags] // indicates bitwise operations occur on this enum
public enum DaysOfWeek : byte // byte type to limit size
{
Sunday = 1,
Monday = 2,
Tuesday = 4,
Wednesday = 8,
Thursday = 16,
Friday = 32,
Saturday = 64,
Weekend = Sunday | Saturday,
Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday
}
This enum can then be consumed by using bitwise math. See the below example for some applications.
public static class DaysOfWeekEvaluator
{
public static bool IsWeekends(DaysOfWeek days)
{
return (days & DaysOfWeek.Weekend) == DaysOfWeek.Weekend;
}
public static bool IsAllWeekdays(DaysOfWeek days)
{
return (days & DaysOfWeek.Weekdays) == DaysOfWeek.Weekdays;
}
public static bool HasWeekdays(DaysOfWeek days)
{
return ((int) (days & DaysOfWeek.Weekdays)) > 0;
}
public static bool HasWeekendDays(DaysOfWeek days)
{
return ((int) (days & DaysOfWeek.Weekend)) > 0;
}
}
There is no implicit cast because the enum does not have to use int as the underlying type. If your enum used a uint as the underlying type, for instance, there is no implicit cast from uint to int.
The c# enum is useless.
You can avoid casting from your type AND constrain the values that can be explicitly cast to your type by making a sealed class, and providing implicit/explicit conversion operators.
Provide an implicit operator for converting from your type to a generic int so you don't have to cast.
Provide an explicit operator for converting from an int to your type, which throws an error if the integer fails to meet the constraint, such as (int x) => (x >= 0 && x <= 2).
If using this technique, create a generic immutable base class such as ConstrainedNumber<T>, which has a constructor that accepts a T value and delegate for the constraint: delegate bool NumberConstraint<T>(T value). The constructor should run the value through the constraint delegate, and throw an exception if it fails to meet the constraint. The base class should also take care of the implicit conversion operation to T, and should handle equality by overloading object.Equals(object) and object.GetHashCode(), defining == and != operators for the type ConstrainedNumber<T>, and implementing IEquatable<T> and IEquatable<ConstrainedNumber<T>>. I also recommend defining an copy constructor for the base class, and all derived types. Cloning can then be implemented cleanly in the base class by retrieving the copy constructor via reflection, but this is entirely optional. You can figure out the ConstrainedNumber<T> implementation yourself, unless I've already posted it on stackoverflow somewhere.
You can provide named static readonly values in your derived ConstrainedNumber, so that you can access them just like an enum.
public sealed class ReturnValue: ConstrainedNumber<int>
{
public static readonly NumberConstraint<int> constraint = (int x) => (x >= 0 && x < 3);
public static readonly ReturnValue Success = new ReturnValue(0);
public static readonly ReturnValue FailReason1 = new ReturnValue(1);
public static readonly ReturnValue FailReason2 = new ReturnValue(2);
private ReturnValue( int value ): base( value, constraint ) {}
private ReturnValue( ReturnValue original ): base (original) {} //may be used to support IClonable implementation in base class
public static explicit operator ReturnValue( int value )
{
switch(value) //switching to return an existing instance is more efficient than creating a new one and re-checking the constraint when there is a limited number of allowed values; if the constraint was more generic, such as an even number, then you would instead return a new instance here, and make your constructors public.
{
case 0: return Success;
case 1: return FailReason1;
case 2: return FailReason2;
}
throw new ArgumentException( "Value fails to meet the constraint defined for " + typeof(ReturnValue).FullName + ".", "value" );
}
}
You could use this technique for any constraint. For example, a class called EvenNumber may have a constraint that returns true if the given number is even. In that case, you'd just make your constructors public, and simplify your static conversion operator to just return a new EvenNumber, instead of switching to return one of the limited existing instances.
It could be used like this:
EvenNumber x = (EvenNumber)2;
EvenNumber y = (EvenNumber)3; //throws exception "Value fails to meet the constraint defined for {namespace}.EvenNumber." A c# enum would stupidly allow such a cast, creating an invalid EvenNumber, breaking the object-oriented model
int z = x; //implicit conversion, no cast necessary;
Enums and ints are simply not implicitly castable as per the spec (except for the literal 0, which is allowed for comparison tests / assignments / etc). The explicit cast is all that is needed, though.
Strangely enough, this is not specific to the .NET Framework, but just to C#. As the other commenters have already pointed out, in C# this is basically a specification of the language. The same is not true in VB.NET.
Check out the MSDN reference page for Enums in VB.NET. Note that you can specify the data type of an enumeration at Enum declaration time.
That means, if you really don't want to litter your code with casts to (int), you could write your enumeration in VB.NET, declare it as an integer, then use that Enum from C#.
Remember how they told us computers would make our lives so much simpler? :)
No, you can't avoid casting; as to why there's no implicit conversion, I don't know, but there's not.
You can ascribe this behaviour to the basic intention behind creating Enumerations... to create a set of named constants that can only have specified (or default) values depending on the underlying type.
There are two separate issues to consider, as related to your question:
An Enum value cannot be treated as an int by default because then you would be able to provide any integer and there would be no compile time check to validate that the provided integer does in fact exist as a value in the Enumeration.
Casting becomes necessary since you are trying to convert from the governing type (of type YourCustomEnum which derives from the System.Enum class) to the underlying type, i.e., int or byte, etc.
Risking a Necromancer batch, I still like to post a possibility that didn't come up yet: To use a helper class (resp. struct) that converts implicitly into int and the enum type:
internal struct AutoCaster<T1, T2> {
private T1 Value1 { get; }
private T2 Value2 { get; }
public AutoCaster(T1 value1) {
Value1 = value1;
Value2 = (T2)(object)value1;
}
public AutoCaster(T2 value2) {
Value1 = (T1)(object)value2;
Value2 = value2;
}
public static implicit operator AutoCaster<T1, T2>(T2 input) {
return new AutoCaster<T1, T2>(input);
}
public static implicit operator AutoCaster<T1, T2>(T1 input) {
return new AutoCaster<T1, T2>(input);
}
public static implicit operator T1(AutoCaster<T1, T2> input) {
return input.Value1;
}
public static implicit operator T2(AutoCaster<T1, T2> input) {
return input.Value2;
}
}
As the Main needs a fix return type (int or void) it does not look that elegant in your example, but for other purposes it works just fine:
public static int Main(string[] args) {
return Main2(args);
}
private static AutoCaster<int, ReturnValue> Main2(string[] args) {
return ReturnValue.FailReason2;
}
How about using static Members of a Class?
//enum DocInfos { DocName, DocNumber, DocVersion};
public class DocInfos
{
public static int DocName = 0;
public static int DocNumer = 1;
public static int DocVersion = 2;
}
...
Doc = new string[DocInfos.DocVersion];
// Treffer
Doc[DocInfos.DocName] = TrimB(HTMLLines[lineCounter + 2])
...
I have a few questions about generic classes with Enums.
First of all, I declared my class like this:
public class MyClass<TEnum> where TEnum : struct, IConvertible
But, I'm getting an error that states that my class cannot be used with type arguments.
Moreover, I need to convert the Enum's value to an Integer. How can I do that?
public void SomeMethod(TEnum value)
{
int a = (int)value; // Doesn't work, need to cast to Enum first (?).
}
Thanks.
You already have what you need since you declared requirement IConvertible. Just use ToInt32 etc methods:
public class MyClass<TEnum> where TEnum: struct, IConvertible
{
public int SomeMethod(TEnum value)
{
return value.ToInt32(null);
}
}
For example .NET type decimal is a struct and an IConvertble:
MyClass<decimal> test = new MyClass<decimal>();
Console.WriteLine(test.SomeMethod(150m));
For other classes be sure that you implement IConvertible.
You have declared your generic type parameter to implement IConvertible and that interface has a ToInt32 method.
I have an enum like:
public enum Test:int
{
A=1,
B=2
}
So here I know my enum is an int type but if I want to do something like following:
int a = Test.A;
this doesn't work.
If I have a class like:
public class MyTest
{
public static int A =1;
}
I can say ,
int a = MyTest.A;
Here I don't need to cast A to int explicitly.
So here I know my enum is an int type
No, it's not. It has an underlying type of int, but it's a separate type. Heck, that's half the point of having enums in the first place - that you can keep the types separate.
When you want to convert between an enum value and its numeric equivalent, you cast - it's not that painful, and it keeps your code cleaner in terms of type safety. Basically it's one of those things where the rarity of it being the right thing to do makes it appropriate to make it explicit.
EDIT: One oddity that you should be aware of is that there is an implicit conversion from the constant value 0 to the enum type:
Test foo = 0;
In fact, in the MS implementation, it can be any kind of constant 0:
Test surprise = 0.0;
That's a bug, but one which it's too late to fix :)
I believe the rest for this implicit conversion was to make it simpler to check whether any bits are set in a flags enum, and other comparisons which would use "the 0 value". Personally I'm not a fan of that decision, but it's worth at least being aware of it.
"The underlying type specifies how much storage is allocated for each enumerator. However, an explicit cast is needed to convert from enum type to an integral type".
With your updated example:
public class MyTest
{
public static int A =1;
}
And usage:
int a = MyTest.A;
That's not how enums look. Enums look more like (comments are places where we differ from a real enum):
public struct MyTest /* Of course, this isn't correct, because we'll inherit from System.ValueType. An enum should inherit from System.Enum */
{
private int _value; /* Should be marked to be treated specially */
private MyTest(int value) /* Doesn't need to exist, since there's some CLR fiddling */
{
_value = value;
}
public static explicit operator int(MyTest value) /* CLR provides conversions automatically */
{
return value._value;
}
public static explicit operator MyTest(int value) /* CLR provides conversions automatically */
{
return new MyTest(value);
}
public static readonly MyTest A = new MyTest(1); /* Should be const, not readonly, but we can't do a const of a custom type in C#. Also, is magically implicitly converted without calling a constructor */
public static readonly MyTest B = new MyTest(2); /* Ditto */
}
Yes, you can easily get to the "underlying" int value, but the values of A and B are still strongly typed as being of type MyTest. This makes sure you don't accidentally use them in places where they're not appropriate.
The enum values are not of int type. int is the base type of the enum. The enums are technically ints but logically (from the perspective of the C# language) not. int (System.Int32) is the base type of all enums by default, if you don't explicitly specify another one.
You enum is of type Test. It is not int just because your enum has integers values.
You can cast your enum to get the int value:
int a = (int) Test.A;
If I have the following enum:
public enum ReturnValue{
Success = 0,
FailReason1 = 1,
FailReason2 = 2
//Etc...
}
Can I avoid casting when I return, like this:
public static int main(string[] args){
return (int)ReturnValue.Success;
}
If not, why isn't an enum value treated as an int by default?
enums are supposed to be type safe. I think they didn't make them implicitly castable to discourage other uses. Although the framework allows you to assign a constant value to them, you should reconsider your intent. If you primarily use the enum for storing constant values, consider using a static class:
public static class ReturnValue
{
public const int Success = 0;
public const int FailReason1 = 1;
public const int FailReason2 = 2;
//Etc...
}
That lets you do this.
public static int main(string[] args){
return ReturnValue.Success;
}
EDIT
When you do want to provide values to an enum is when you want to combine them. See the below example:
[Flags] // indicates bitwise operations occur on this enum
public enum DaysOfWeek : byte // byte type to limit size
{
Sunday = 1,
Monday = 2,
Tuesday = 4,
Wednesday = 8,
Thursday = 16,
Friday = 32,
Saturday = 64,
Weekend = Sunday | Saturday,
Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday
}
This enum can then be consumed by using bitwise math. See the below example for some applications.
public static class DaysOfWeekEvaluator
{
public static bool IsWeekends(DaysOfWeek days)
{
return (days & DaysOfWeek.Weekend) == DaysOfWeek.Weekend;
}
public static bool IsAllWeekdays(DaysOfWeek days)
{
return (days & DaysOfWeek.Weekdays) == DaysOfWeek.Weekdays;
}
public static bool HasWeekdays(DaysOfWeek days)
{
return ((int) (days & DaysOfWeek.Weekdays)) > 0;
}
public static bool HasWeekendDays(DaysOfWeek days)
{
return ((int) (days & DaysOfWeek.Weekend)) > 0;
}
}
There is no implicit cast because the enum does not have to use int as the underlying type. If your enum used a uint as the underlying type, for instance, there is no implicit cast from uint to int.
The c# enum is useless.
You can avoid casting from your type AND constrain the values that can be explicitly cast to your type by making a sealed class, and providing implicit/explicit conversion operators.
Provide an implicit operator for converting from your type to a generic int so you don't have to cast.
Provide an explicit operator for converting from an int to your type, which throws an error if the integer fails to meet the constraint, such as (int x) => (x >= 0 && x <= 2).
If using this technique, create a generic immutable base class such as ConstrainedNumber<T>, which has a constructor that accepts a T value and delegate for the constraint: delegate bool NumberConstraint<T>(T value). The constructor should run the value through the constraint delegate, and throw an exception if it fails to meet the constraint. The base class should also take care of the implicit conversion operation to T, and should handle equality by overloading object.Equals(object) and object.GetHashCode(), defining == and != operators for the type ConstrainedNumber<T>, and implementing IEquatable<T> and IEquatable<ConstrainedNumber<T>>. I also recommend defining an copy constructor for the base class, and all derived types. Cloning can then be implemented cleanly in the base class by retrieving the copy constructor via reflection, but this is entirely optional. You can figure out the ConstrainedNumber<T> implementation yourself, unless I've already posted it on stackoverflow somewhere.
You can provide named static readonly values in your derived ConstrainedNumber, so that you can access them just like an enum.
public sealed class ReturnValue: ConstrainedNumber<int>
{
public static readonly NumberConstraint<int> constraint = (int x) => (x >= 0 && x < 3);
public static readonly ReturnValue Success = new ReturnValue(0);
public static readonly ReturnValue FailReason1 = new ReturnValue(1);
public static readonly ReturnValue FailReason2 = new ReturnValue(2);
private ReturnValue( int value ): base( value, constraint ) {}
private ReturnValue( ReturnValue original ): base (original) {} //may be used to support IClonable implementation in base class
public static explicit operator ReturnValue( int value )
{
switch(value) //switching to return an existing instance is more efficient than creating a new one and re-checking the constraint when there is a limited number of allowed values; if the constraint was more generic, such as an even number, then you would instead return a new instance here, and make your constructors public.
{
case 0: return Success;
case 1: return FailReason1;
case 2: return FailReason2;
}
throw new ArgumentException( "Value fails to meet the constraint defined for " + typeof(ReturnValue).FullName + ".", "value" );
}
}
You could use this technique for any constraint. For example, a class called EvenNumber may have a constraint that returns true if the given number is even. In that case, you'd just make your constructors public, and simplify your static conversion operator to just return a new EvenNumber, instead of switching to return one of the limited existing instances.
It could be used like this:
EvenNumber x = (EvenNumber)2;
EvenNumber y = (EvenNumber)3; //throws exception "Value fails to meet the constraint defined for {namespace}.EvenNumber." A c# enum would stupidly allow such a cast, creating an invalid EvenNumber, breaking the object-oriented model
int z = x; //implicit conversion, no cast necessary;
Enums and ints are simply not implicitly castable as per the spec (except for the literal 0, which is allowed for comparison tests / assignments / etc). The explicit cast is all that is needed, though.
Strangely enough, this is not specific to the .NET Framework, but just to C#. As the other commenters have already pointed out, in C# this is basically a specification of the language. The same is not true in VB.NET.
Check out the MSDN reference page for Enums in VB.NET. Note that you can specify the data type of an enumeration at Enum declaration time.
That means, if you really don't want to litter your code with casts to (int), you could write your enumeration in VB.NET, declare it as an integer, then use that Enum from C#.
Remember how they told us computers would make our lives so much simpler? :)
No, you can't avoid casting; as to why there's no implicit conversion, I don't know, but there's not.
You can ascribe this behaviour to the basic intention behind creating Enumerations... to create a set of named constants that can only have specified (or default) values depending on the underlying type.
There are two separate issues to consider, as related to your question:
An Enum value cannot be treated as an int by default because then you would be able to provide any integer and there would be no compile time check to validate that the provided integer does in fact exist as a value in the Enumeration.
Casting becomes necessary since you are trying to convert from the governing type (of type YourCustomEnum which derives from the System.Enum class) to the underlying type, i.e., int or byte, etc.
Risking a Necromancer batch, I still like to post a possibility that didn't come up yet: To use a helper class (resp. struct) that converts implicitly into int and the enum type:
internal struct AutoCaster<T1, T2> {
private T1 Value1 { get; }
private T2 Value2 { get; }
public AutoCaster(T1 value1) {
Value1 = value1;
Value2 = (T2)(object)value1;
}
public AutoCaster(T2 value2) {
Value1 = (T1)(object)value2;
Value2 = value2;
}
public static implicit operator AutoCaster<T1, T2>(T2 input) {
return new AutoCaster<T1, T2>(input);
}
public static implicit operator AutoCaster<T1, T2>(T1 input) {
return new AutoCaster<T1, T2>(input);
}
public static implicit operator T1(AutoCaster<T1, T2> input) {
return input.Value1;
}
public static implicit operator T2(AutoCaster<T1, T2> input) {
return input.Value2;
}
}
As the Main needs a fix return type (int or void) it does not look that elegant in your example, but for other purposes it works just fine:
public static int Main(string[] args) {
return Main2(args);
}
private static AutoCaster<int, ReturnValue> Main2(string[] args) {
return ReturnValue.FailReason2;
}
How about using static Members of a Class?
//enum DocInfos { DocName, DocNumber, DocVersion};
public class DocInfos
{
public static int DocName = 0;
public static int DocNumer = 1;
public static int DocVersion = 2;
}
...
Doc = new string[DocInfos.DocVersion];
// Treffer
Doc[DocInfos.DocName] = TrimB(HTMLLines[lineCounter + 2])
...