Enum conversion to other Enum - c#

I have many Enum types which return from a service and which I want to map to my Enum types.
What I want is to create a mapper class which has all the conversion logic.
I did something like this:
public static class ErrEnumMapper
{
private static Dictionary<FullErrorTypeError, eError> dictionary;
static ErrEnumMapper()
{
var dictionary = new Dictionary<FullErrorTypeError, eError>()
{
{FullErrorTypeError.APP, eError.APPLICATION},
{FullErrorTypeError.INF, eError.INF},
{FullErrorTypeError.NO, eError.NONE},
{FullErrorTypeError.PAX, eError.PASSENGER},
{FullErrorTypeError.SYS, eError.SYSTEM}
};
}
public static eError GetEnum(FullErrorTypeError key)
{
var val = dictionary[key];
if (val != null)
return val;
throw new InvalidOperationException();
}
}
But since I have many other Enums, in this way, I will have to create many static fields (like the "dictionary" fields) and their equivalent method (Like "GetEnum")...is there a better way to do this?
Generic maybe?

Unless the integral values or names are the same for both sets of enums are the same, you can't transpose from one enum value to another without some sort of manual mapping.
Some suggestions:
Reuse the original enums if possible
Keep the integer values of the mapped enum the same as the original enum, so you can just cast from one to another.
Use a convention for the enum names so you can map from one to the other.
Use a custom attribute on each mapped enum value that indicates the correlating original enum value, and have ErrEnumMapper read that attribute. Still manual mapping, just perhaps reorganized.
Of course, in the spirit of KISS, I'd stick with #1, #2, or just deal with the manual mapping.

Maybe I'm not really getting what you mean.. but you can just explicitly cast them if they have the same underlying value:
enum FirstEnum {
ONE,
TWO,
THREE
}
enum SecondEnum {
FOUR,
FIVE,
SIX
}
static void Main(string[] args) {
FirstEnum first = FirstEnum.ONE;
SecondEnum second = (SecondEnum)first;
Console.WriteLine(second); // prints FOUR
}
This allows you to keep your naming convention..

Related

Get and Set the underlying value of an Enum

So I am trying really hard to change the underlying number value of an Enum. Take this example:
[Flags]
public enum Foo
{
Foo = 1,
Bar = 2,
FooBat = 4
}
With a simple extension methods for enums. In his method I want to remove all flags from the enum itself:
public static TEnum GetBaseVersionOfEnum<TEnum>(this TEnum enumVal) where TEnum : Enum
{
var tempEnum = enumVal & 0 // I would like to do something like that. e.g. setting its underlying value to zero.
return tempEnum;
}
Note that it is possible to set an enum to zero, even if there is no matching enum member.
To clarify what I want to achieve, here a few samples:
Foo.Bar.GetBaseVersionOfEnum() should return Foo with the value of 0.
(Foo.Bar | Foo.Foo).GetBaseVersionOfEnum() should return Foo with the value of 0.
I actually achieved that, but it is hella ugly, at least IMO, by using some reflection. I really hope there is a cleaner and faster way to do this.
var dynamicVal = (dynamic)enumVal;
dynamicVal.value__ = 0;
var tempEnum = (Enum)dynamicVal;
I actually stumbled over the value__ field by some testing with reflection, which revealed that there is actually a public field which exposes the current value.
This also makes me wonder why you can't access it by using the dot (enumVal.value__)... I guess it is some kind of runtime field.
I might be deeply confused by your question, but to me it seems you're trying to make a convoluted way of saying default:
public static TEnum GetBaseVersionOfEnum<TEnum>(this TEnum enumVal) where TEnum : Enum
{
return default;
}
The default value for an enum is all-zero bits (the default for the underlying value type). But why do you need a helper for that at all? You can literally say
Foo allzero;
And you get an all-zero enum of your type. Or say
myExistingEnum = default;
to zero an existing variable out.

define a function to accept a specific list parameter

I want to define a function with a parameter, that paramter must be a specific, defined in a list (for example)
i remember doing this years ago but my memory has failed me.
example
public void foo(specific choice list defined in my class){}
specific-list = x,y,z
consume it list this (i think)
foo(myclass.x)
To expand on #kaffekopp's comment, it seems likely that you are talking about an enum, i.e.
public enum MyEnum // declare the enum type (optional: specify an underlying integer type)
{
Apple, // define the choices (note: enums are **not** strictly enforced;
Pear, // they are just named integers, and at runtime you can be surprised to find
Bicycle, // that the actual value is 42, a value you never defined)
}
with (on MyClass):
public MyEnum SomeProp {get;set;} // define a property as being of that enum type
and:
public void Foo(MyEnum option) {...} // define a method that takes a parameter of the type
then either:
Foo(MyEnum.Bicycle); // passing a constant/literal
or:
MyClass obj = ...
Foo(obj.SomeProp); // passing an existing value from somewhere

treat Enum as generic?

I'm trying to find a way to treat enums generically but I can't find a way to make it work. Say I have several enums declared something like this:
public enum ABC {
One,
Two,
Three
}
public enum DEF {
Four,
Five,
Six
}
and I want to write a method that takes an Enum as a parameter and simply returns name of the enum like this:
public string GetEnumName(Enum anEnum) {
return anEnum.GetType().Name;
}
but if I call it like GetEnumName(DEF); I get the 'is a type being used as a variable' error. Any ideas? thanks
EDIT Sorry judging by the replies I may not have been clear enough. I merely chose GetEnumName as a very simplistic example to illustrate the problem, not how to get the name from a type. Basically I want a method that I can pass ANY enum to and have it act on that enum directly, thanks
Use:
public static string GetTypeName<T>()
{
return typeof(T).Name;
}
Usage:
var result = GetTypeName<DEF>();
Perhaps this will do the trick?
public static class EnumExtensions
{
public static string GetEnumName<T>(this T value) where T : struct
{
var type = typeof(T);
if (!type.IsEnum)
throw new InvalidOperationException(string.Format("{0} is not an enum", type));
return type.GetEnumName(value);
}
}
What you want to write is something like this:
public string GetEnumName<T>() where T : Enum
{
return typeof(T).Name;
}
That is, a generic method with a type parameter constraint.
Unfortunately, there is no way to define such a constraint for enums in C# (nor it is possible to define one for delegates). People usually go for the solution mentioned by #ananthonline.
In fact such constraint is not supported by the C# language but it is supported at the CLR level. Using a tool like Mono.Cecil for example can help you to modify your assembly and apply the constraint on the method after you get it compiled.
Have a look to this article: Constraining generic constraints
You'll find a tool which eases the process of applying non-C#-supported generic type parameter constraints: Cecil constraint patcher
And don't forget there are a lot of useful static methods on the Enum class if you want to work with the names and values of your enum members.
Your problem is that you are passing in the type instead of the System.Type. Change your method to this:
public string GetEnumName(Type enumType) {
return enumType.Name;
}
Just pass the type:
public string GetEnumName(Type enumType)
{
return enumType.Name;
}
And
GetEnumName(typeof(ABC));
At this point if your method does nothing else you could probably just use typeof(ABC).Name instead.
You can't. Generic constraints are not allowed on enum types (including System.Enum). Use Enum.GetName instead.

Get a List of available Enums

I have the enum structure as follows:
public enum MyEnum
{
One=1,
Two=2,
Three=3
}
Now I want to get a list of MyEnum, i.e., List<MyEnum> that contains all the One, Two Three. Again, I am looking for a one liner that does the thing. I came out with a LINQ query but it was unsatisfactory because it was a bit too long, I think:
Enum.GetNames(typeof(MyEnum))
.Select(exEnum =>
(MyEnum)Enum.Parse(typeof(MyEnum), exEnum))
.ToList();
A better suggestion?
Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>();
I agree with #mquander's code.
However, I would suggest you also cache the list, since it's extremely unlikely to change over the course of the execution of your program. Put it in a static readonly variable in some global location:
public static class MyGlobals
{
public static readonly List<MyEnum> EnumList =
Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().ToList();
}
Not a one liner (well the implementation isn't, but the method is :P), but perhaps add something like this to a tools/ utility class which will return a generic list:
public static List<T> EnumToList<T>()
{
Type enumType = typeof(T);
// Can't use type constraints on value types, so have to do check like this
if (enumType.BaseType != typeof(Enum))
throw new ArgumentException("T must be of type System.Enum");
return new List<T>(Enum.GetValues(enumType) as IEnumerable<T>);
}

How to convert from System.Enum to base integer?

I'd like to create a generic method for converting any System.Enum derived type to its corresponding integer value, without casting and preferably without parsing a string.
Eg, what I want is something like this:
// Trivial example, not actually what I'm doing.
class Converter
{
int ToInteger(System.Enum anEnum)
{
(int)anEnum;
}
}
But this doesn't appear to work. Resharper reports that you can not cast expression of type 'System.Enum' to type 'int'.
Now I've come up with this solution but I'd rather have something more efficient.
class Converter
{
int ToInteger(System.Enum anEnum)
{
return int.Parse(anEnum.ToString("d"));
}
}
Any suggestions?
If you don't want to cast,
Convert.ToInt32()
could do the trick.
The direct cast (via (int)enumValue) is not possible. Note that this would also be "dangerous" since an enum can have different underlying types (int, long, byte...).
More formally: System.Enum has no direct inheritance relationship with Int32 (though both are ValueTypes), so the explicit cast cannot be correct within the type system
I got it to work by casting to an object and then to an int:
public static class EnumExtensions
{
public static int ToInt(this Enum enumValue)
{
return (int)((object)enumValue);
}
}
This is ugly and probably not the best way. I'll keep messing with it, to see if I can come up with something better....
EDIT: Was just about to post that Convert.ToInt32(enumValue) works as well, and noticed that MartinStettner beat me to it.
public static class EnumExtensions
{
public static int ToInt(this Enum enumValue)
{
return Convert.ToInt32(enumValue);
}
}
Test:
int x = DayOfWeek.Friday.ToInt();
Console.WriteLine(x); // results in 5 which is int value of Friday
EDIT 2: In the comments, someone said that this only works in C# 3.0. I just tested this in VS2005 like this and it worked:
public static class Helpers
{
public static int ToInt(Enum enumValue)
{
return Convert.ToInt32(enumValue);
}
}
static void Main(string[] args)
{
Console.WriteLine(Helpers.ToInt(DayOfWeek.Friday));
}
If you need to convert any enum to its underlying type (not all enums are backed by int) then you can use:
return System.Convert.ChangeType(
enumValue,
Enum.GetUnderlyingType(enumValue.GetType()));
Why do you need to reinvent the wheel with a helper method? It's perfectly legal to cast an enum value to its underlying type.
It's less typing, and in my opinion more readable, to use...
int x = (int)DayOfWeek.Tuesday;
...rather than something like...
int y = Converter.ToInteger(DayOfWeek.Tuesday);
// or
int z = DayOfWeek.Tuesday.ToInteger();
From my answer here:
Given e as in:
Enum e = Question.Role;
Then these work:
int i = Convert.ToInt32(e);
int i = (int)(object)e;
int i = (int)Enum.Parse(e.GetType(), e.ToString());
int i = (int)Enum.ToObject(e.GetType(), e);
The last two are plain ugly. The first one should be more readable, though the second one is much faster. Or may be an extension method is the best, best of both worlds.
public static int GetIntValue(this Enum e)
{
return e.GetValue<int>();
}
public static T GetValue<T>(this Enum e) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
{
return (T)(object)e;
}
Now you can call:
e.GetValue<int>(); //or
e.GetIntValue();
Casting from a System.Enum to an int works fine for me (it's also on the MSDN). Perhaps it's a Resharper bug.
Since Enums are restricted to byte, sbyte, short, ushort, int, uint, long and ulong, we can make some assumptions.
We can avoid exceptions during conversion by using the largest available container. Unfortunately, which container to use is not clear because ulong will blow up for negative numbers and long will blow up for numbers between long.MaxValue and ulong.MaxValue. We need to switch between these choices based on the underlying type.
Of course, you still need to decide what to do when the result doesn't fit inside an int. I think casting is okay, but there are still some gotchas:
for enums based on a type with a field space larger than int (long and ulong), it's possible some enums will evaluate to the same value.
casting a number larger than int.MaxValue will throw an exception if you are in a checked region.
Here's my suggestion, I'll leave it to the reader to decide where to expose this function; as a helper or an extension.
public int ToInt(Enum e)
{
unchecked
{
if (e.GetTypeCode() == TypeCode.UInt64)
return (int)Convert.ToUInt64(e);
else
return (int)Convert.ToInt64(e);
}
}
If you read the code for Convert.ToInt32, you can see that it casts the Enum to IConvertible, then calls ToInt32(null).
Don't forget that the Enum type itself has a bunch of static helper functions in it. If all you want to do is convert an instance of the enum to its corresponding integer type, then casting is probably the most efficient way.
I think ReSharper is complaining because Enum isn't an enumeration of any particular type, and enumerations themselves derive from a scalar valuetype, not Enum. If you need adaptable casting in a generic way, I would say this could suite you well (note that the enumeration type itself is also included in the generic:
public static EnumHelpers
{
public static T Convert<T, E>(E enumValue)
{
return (T)enumValue;
}
}
This could then be used like so:
public enum StopLight: int
{
Red = 1,
Yellow = 2,
Green = 3
}
// ...
int myStoplightColor = EnumHelpers.Convert<int, StopLight>(StopLight.Red);
I can't say for sure off the top of my head, but the above code might even be supported by C#'s type inference, allowing the following:
int myStoplightColor = EnumHelpers.Convert<int>(StopLight.Red);

Categories

Resources