How can I get the max int value from an enum using generics?
I have tried the following however it displays the following compilation error:
Cannot implicitly convert T to int
int maxValue = GetMaxValue<SomeEnum>(typeof(SomeEnum)); //expecting 2
private static int GetMaxValue<T>(Type enumType)
{
return Enum.GetValues(enumType).Cast<T>().Max();
}
public enum SomeEnum
{
ValueOne = 1,
Value = 2
}
In case of C# 7.3 or later version, you can implement Sweeper's idea in a bit different way (with a help of where T : Enum constraint):
public static T GetMaxValue<T>() where T : Enum {
return Enum.GetValues(typeof(T)).Cast<T>().Max();
}
...
SomeEnum max = GetMaxValue<SomeEnum>();
Please, note, that the result is enum itself and that's why we don't have any problems with enum underlying type (byte, short int, long)
You need to cast to int, not T. And you don't actually need the Type parameter (unless you don't know the type at compile time), since you can just do typeof(T):
private static int GetMaxValue<T>()
{
return Enum.GetValues(typeof(T)).Cast<int>().Max();
}
// usage:
GetMaxValue<SomeEnum>() // 2
If your enums have long or some other type as the underlying type, you can specify another type parameter to cast them to:
private static U GetMaxValue<T, U>() where U : struct
{
return Enum.GetValues(typeof(T)).Cast<U>().Max();
}
// usage:
GetMaxValue<SomeLongEnum, long>()
Use Convert.ToInt32
return Convert.ToInt32(Enum.GetValues(enumType).Cast<T>().Max());
But usually I do this, more faster than calling GetValues
public enum SomeEnum
{
ValueOne = 1,
Value = 2,
END
}
return (int)(SomeEnum.END - 1);
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 want to use Interlocked.CompareExchange with an enum type that inherits from int, like so:
public enum MyEnum : int { A, B }
public class MyClass
{
private static readonly MyEnum s_field = MyEnum.A;
public void Foo()
{
if (Interlocked.CompareExchange(ref s_field, MyEnum.B, MyEnum.A) == MyEnum.A)
{
Console.WriteLine("Changed from A to B");
}
}
}
However, CompareExchange only works with reference types and select value types (see here). Since a MyEnum is really an int underneath the skin, I thought I should be able to pass it as a ref int:
// should call CompareExchange(ref int, int, int) overload
Interlocked.CompareExchange(ref s_field, (int)MyEnum.B, (int)MyEnum.A);
However, this doesn't seem to work either. I get the following error:
Error CS1503: Argument 1: cannot convert from 'ref MyEnum' to 'ref int'
Casting before passing it in, e.g. ref (int)s_field, doesn't help either.
How can I fix this? Is there any way to use CompareExchange with enums, or must I use ints instead?
Would you want to use union?
public enum MyEnum : int { A, B }
[StructLayout(LayoutKind.Explicit)]
struct IntEnumUnion
{
[FieldOffset(0)]
public MyEnum Enum;
[FieldOffset(0)]
public int Int;
}
private static IntEnumUnion s_field;
s_field.Enum = MyEnum.A;
if (Interlocked.CompareExchange(ref s_field.Int, (int)MyEnum.B, (int)MyEnum.A)
== (int)MyEnum.A)
{
Console.WriteLine("Changed from A to B");
}
Of course, it is little cumbersome...
What about converting the value after the evaluation?
int value = (int)MyEnum.A;
var result = Interlocked.CompareExchange(ref value, (int)MyEnum.A, (int)MyEnum.B);
if((MyEnum)result == MyEnum.A)
System.Console.WriteLine("Changed from A to B");
Maybe you can just use:
static readonly object lockInstance = new object();
public static TSimple CompareExchange<TSimple>(ref TSimple location1, TSimple value, TSimple comparand)
{
lock (lockInstance)
{
var location1Read = location1;
if (EqualityComparer<TSimple>.Default.Equals(location1Read, comparand))
{
// location1 write
location1 = value;
}
return location1Read;
}
}
Caution: The lock thing only prevents changes to location1 occurring through this particular method. It cannot prevent other threads from manipulating location1 by other means while my method runs. If this is a problem, maybe use int and have public static class MyEnum { public const int A = 0; public const int B = 1; }.
I believe this is now possible with the Unsafe class which was introduced in .NET Core. Run this to install the package containing the class into your app:
Install-Package System.Runtime.CompilerServices.Unsafe
Then you can do Interlocked.CE(ref Unsafe.As<MyEnum, int>(ref s_field), (int)MyEnum.B, (int)MyEnum.A). Note that this requires C# 7 language support for ref returns, so you need to have VS2017 or later.
sorry for asking this question but i didn't found the right solution for this task:
I've got a Enum, which is named "myEnum" (MyEnum isn't known by the function)
I Need to get the int value of a Value of myEnum
Example:
A Programmer named its enum "myEnum":
public enum myEnum
{
foo = 1,
bar = 2,
}
my function should do the following:
Get the Value of "foo" of "myEnum" by string
function should opened by:
public int GetValueOf(string EnumName, string EnumConst)
{
}
so when Programmer A opens it by :
int a = GetValueOf("myEnum","foo");
it should return 1
and when Programmer B has an Enum named "mySpace", wants to return "bar" with Value 5
int a = GetValueOf("mySpace","bar")
should return 5
how can i do this?
You can use Enum.Parse to do this, but you'd need the fully qualified type name of the Enum type, ie: "SomeNamespace.myEnum":
public static int GetValueOf(string enumName, string enumConst)
{
Type enumType = Type.GetType(enumName);
if (enumType == null)
{
throw new ArgumentException("Specified enum type could not be found", "enumName");
}
object value = Enum.Parse(enumType, enumConst);
return Convert.ToInt32(value);
}
Also note that this uses Convert.ToInt32 instead of a cast. This will handle enum values with underlying types which are not Int32. This will still throw an OverflowException, however, if your enum has an underlying value outside of the range of an Int32 (ie: if it's a ulong as the value is >int.MaxValue).
Please try
int result = (int) Enum.Parse(Type.GetType(EnumName), EnumConst);
I suppose you're trying to instance the enum from the string value (it's name) then I'll suggest you to get it members via reflection and then compare.
Please be aware reflection adds a bit of overhead.
It's not clear to me if the name of the enum type must be specified as a string.
You need to use Enum.TryParse to get the value of the Enum. In combination with a generic method, you could do something like this:
public int? GetValueOf<T>(string EnumConst) where T : struct
{
int? result = null;
T temp = default(T);
if (Enum.TryParse<T>(EnumConst, out temp))
{
result = Convert.ToInt32(temp);
}
return result;
}
To call it use this:
int? result = GetValueOf<myEnum>("bar");
if (result.HasValue)
{
//work with value here.
}
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])
...