enum backward compatibility - c#

I have enum A which became two enums in version 2 enum B and C.
There is a function GetSpecificEnum() which returns enum A for version 1 and should return enum B and C for version 2 and above. Function itself doing some calculations and returns enum which meets my scenario.
My problem is to properly define this function which can return two versions.
I can always create two functions and somehow get calculations as private refactored method but i'm trying to avoid this.
Is there a way to do it ?
public ?? GetSpecificEnum()
{
if(version == 1)
{
//do some stuff
return A.SomeValue;
}
else
{
// do some stuff
return KeyValuePair<B, C>(B.SomeValue, C.SomeValue);
}
}

You can use the system type Enum as the return value for GetSpecificEnum. Your code will then have to check the type for the return, and handle it accordingly.
public enum A
{
ONE,TWO
};
public enum B
{
THREE,
FOUR
};
public Enum GetThing(int version)
{
return version == 1 ? (Enum)A.ONE : B.THREE;
}
public void DoThing()
{
Enum e = GetThing(1);
if (e is A)
{
// handle A
A _a = (A)e;
}
else
{
// handle B
}
}

You could do something like this if you are an API/product provider:
public enum OldEnum
{
One,
Two,
Three
}
public enum NewPart1
{
One,
Two
}
public enum NewPart2
{
Three
}
[Obsolete("This method is intended to by used be previous versions")]
public OldEnum GetEnum(someparameters here)
{
// Some processing here
return OldEnum.One;
}
public NewPart1 GetEnum(someparameters here)
{
// Do something here
return NewPart1.One;
}
public NewPart2 GetEnum(someparameters here)
{
// Do something here
return NewPart2.Three;
}
If your enumerations are split of old enumeration, you do not really need to make change to code. In the end, we are dealing with integers. Please note, split enumerations still retain same integer values as earlier. You can then just cast the integer value and send it across.

Related

How to return enum from property

Is there a way how to return full enum by property? Here is example of what I want to do:
// MyEnums.cs
public enum Languages
{
cs = 0,
pl = 1,
en = 2,
de = 3,
}
// General.cs
public static MyEnums.Languages Languages
{
get
{
return MyEnums.Languages;
}
}
enum is a type, i guess you actually want to get all enum-values. You could use this wrapper:
public static class EnumWrapper<T> where T : struct
{
public static T[] Values
{
get
{
Type ofT = typeof(T);
if (!ofT.IsEnum) throw new ArgumentException("Must be enum type");
return Enum.GetValues(ofT).Cast<T>().ToArray();
}
}
}
// ...
Languages[] languages = EnumWrapper<Languages>.Values;
If you want to return all available values defined in the enum, you can use
Enum.GetValues(typeof(MyEnums.Languages));
and modify your method so it returns a MyEnums.Languages[] (or a List<MyEnums.Languages>, which is always easier to manage for calling code)
To get all values in the enum, use Enum.GetValues. You might also want to cast it back to the correct type:
Languages[] languages = Enum.GetValues(typeof(Languages)).Cast<Languages>().ToArray();
// languages is an array containing { Languages.cs, Languages.pl, Languages.en, Languages.de }

What is the best way to implement a Rust enum in C#?

I have an entity that can be in one of different states (StateA, StateB and StateC), and in each of them have relevant data of distinct types (TStateA, TStateB, TStateC). Enums in Rust represent this perfectly. What is the best way to implement something like this in C#?
This question may appear similar, but enums in Rust and unions in C are significantly different.
You need a class to represent your Entity
class Entity {States state;}
Then you need a set of classes to represent your states.
abstract class States {
// maybe something in common
}
class StateA : MyState {
// StateA's data and methods
}
class StateB : MyState {
// ...
}
Then you need to write code like
StateA maybeStateA = _state as StateA;
If (maybeStateA != null)
{
- do something with the data in maybeStateA
}
C# does not have a nice way of writing code for this yet, maybe the Pattern Matching that is being considered for C#.next would help.
I think you should rethink your design to use object relationships and containment, trying to take a design that works in rust and force it into C# may not be the best option.
This might be crazy, but if you are hard-up about emulating Rust-like enums in C#, you could do it with some generics. Bonus: you keep type-safety and also get Intellisense out of the deal! You'll lose a little flexibility with various value types, but I think the safety is probably worth the inconvenience.
enum Option
{
Some,
None
}
class RustyEnum<TType, TValue>
{
public TType EnumType { get; set; }
public TValue EnumValue { get; set; }
}
// This static class basically gives you type-inference when creating items. Sugar!
static class RustyEnum
{
// Will leave the value as a null `object`. Not sure if this is actually useful.
public static RustyEnum<TType, object> Create<TType>(TType e)
{
return new RustyEnum<TType, object>
{
EnumType = e,
EnumValue = null
};
}
// Will let you set the value also
public static RustyEnum<TType, TValue> Create<TType, TValue>(TType e, TValue v)
{
return new RustyEnum<TType, TValue>
{
EnumType = e,
EnumValue = v
};
}
}
void Main()
{
var hasSome = RustyEnum.Create(Option.Some, 42);
var hasNone = RustyEnum.Create(Option.None, 0);
UseTheEnum(hasSome);
UseTheEnum(hasNone);
}
void UseTheEnum(RustyEnum<Option, int> item)
{
switch (item.EnumType)
{
case Option.Some:
Debug.WriteLine("Wow, the value is {0}!", item.EnumValue);
break;
default:
Debug.WriteLine("You know nuffin', Jon Snow!");
break;
}
}
Here's another sample demonstrating the use of a custom reference type.
class MyComplexValue
{
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
public override string ToString()
{
return string.Format("A: {0}, B: {1}, C: {2}", A, B, C);
}
}
void Main()
{
var hasSome = RustyEnum.Create(Option.Some, new MyComplexValue { A = 1, B = 2, C = 3});
var hasNone = RustyEnum.Create(Option.None, null as MyComplexValue);
UseTheEnum(hasSome);
UseTheEnum(hasNone);
}
void UseTheEnum(RustyEnum<Option, MyComplexValue> item)
{
switch (item.EnumType)
{
case Option.Some:
Debug.WriteLine("Wow, the value is {0}!", item.EnumValue);
break;
default:
Debug.WriteLine("You know nuffin', Jon Snow!");
break;
}
}
This looks a lot like Abstract Data Types in functional languages. There's no direct support for this in C#, but you can use one abstract class for the data type plus one sealed class for each data constructor.
abstract class MyState {
// maybe something in common
}
sealed class StateA : MyState {
// StateA's data and methods
}
sealed class StateB : MyState {
// ...
}
Of course, there's nothing prohibiting you from adding a StateZ : MyState class later, and the compiler won't warn you that your functions are not exhaustive.
Just from the back of my head, as a quick implementation...
I would first declare the Enum type and define enumerate items normally.
enum MyEnum{
[MyType('MyCustomIntType')]
Item1,
[MyType('MyCustomOtherType')]
Item2,
}
Now I define the Attribute type MyTypeAttribute with a property called TypeString.
Next, I need to write an extension method to extract the Type for each enum item (first in string, then later reflect to real type):
public static string GetMyType(this Enum eValue){
var _nAttributes = eValue.GetType().GetField(eValue.ToString()).GetCustomAttributes(typeof (MyTypeAttribute), false);
// handle other stuff if necessary
return ((MyTypeAttribute) _nAttributes.First()).TypeString;
}
Finally, get the real type using reflection...
I think the upside of this approach is easy to use later in the code:
var item = MyEnum.SomeItem;
var itemType = GetType(item.GetMyType());
I've been looking into Rust recently and been thinking the same questions. The real problem is the absence of the Rust deconstruction pattern matching but the type itself is long-winded but relatively straightforward if you are willing to use boxing:
// You need a new type with a lot of boilerplate for every
// Rust-like enum but they can all be implemented as a struct
// containing an enum discriminator and an object value.
// The struct is small and can be passed by value
public struct RustyEnum
{
// discriminator type must be public so we can do a switch because there is no equivalent to Rust deconstructor
public enum DiscriminatorType
{
// The 0 value doesn't have to be None
// but it must be something that has a reasonable default value
// because this is a struct.
// If it has a struct type value then the access method
// must check for Value == null
None=0,
IVal,
SVal,
CVal,
}
// a discriminator for users to switch on
public DiscriminatorType Discriminator {get;private set;}
// Value is reference or box so no generics needed
private object Value;
// ctor is private so you can't create an invalid instance
private RustyEnum(DiscriminatorType type, object value)
{
Discriminator = type;
Value = value;
}
// union access methods one for each enum member with a value
public int GetIVal() { return (int)Value; }
public string GetSVal() { return (string)Value; }
public C GetCVal() { return (C)Value; }
// traditional enum members become static readonly instances
public static readonly RustyEnum None = new RustyEnum(DiscriminatorType.None,null);
// Rusty enum members that have values become static factory methods
public static RustyEnum FromIVal(int i)
{
return new RustyEnum(DiscriminatorType.IVal,i);
}
//....etc
}
Usage is then:
var x = RustyEnum::FromSVal("hello");
switch(x.Discriminator)
{
case RustyEnum::DiscriminatorType::None:
break;
case RustyEnum::DiscriminatorType::SVal:
string s = x.GetSVal();
break;
case RustyEnum::DiscriminatorType::IVal:
int i = x.GetIVal();
break;
}
If you add some extra public const fields this could be reduced to
var x = RustyEnum::FromSVal("hello");
switch(x.Discriminator)
{
case RustyEnum::None:
break;
case RustyEnum::SVal:
string s = x.GetSVal();
break;
case RustyEnum::IVal:
int i = x.GetIVal();
break;
}
... but you then need a different name for creating the valueless members (like None in this example)
It seems to me that if the C# compiler was to implement rust enums without changing the CLR then this is the sort of code that it would generate.
It would be easy enough to create a .ttinclude to generate this.
Deconstruction is not as nice as Rust match but there is no alternative that is both efficient and idiot proof (the inefficient way is to use something like
x.IfSVal(sval=> {....})
To summarize my rambling - It can be done but it's unlikely to be worth the effort.
Short answer you can't. Even if you feel you can just don't do it you would shoot yourself in foot in doing so. We'll have to wait for the C# team to come up with a type with something like below
struct lives on stack in most cases this means it has a fixed size in memory
What we are expecting is sort of multiple struct with different layout but still fits in one decided stack of memory. The way rust handles this is by using the memory size of largest of the group for example
# Right now:
struct A { int a } # 4 bytes
struct B { int a, int b } # 8 bytes
# Can do but highly don't recommend would be waste of precious time, memory and cpu
struct AB {
A a,
B b
} # 12 bytes + 2 bytes to keep bool to check which struct should be used in code
# Future/Should be
super struct AB {
A(int),
B(int, int)
} # 8 bytes
Never did anything in Rust, but looking at the docs it seams to me that you would have to implement a textbook C# class. Since Rust enums even support functions and implementations of various types.
Probabily an abstract class.

Generic method returning value according to input parameter

I'm new to using generic classes. Here is my question:
I have several enumerations like: x.PlatformType, y.PlatformType, z.PlatformType etc...
public class Helper<T>
{
public T GetPlatformType(Type type)
{
switch (System.Configuration.ConfigurationManager.AppSettings["Platform"])
{
case "DVL":
return // if type is x.PlatformType I want to return x.PlatformType.DVL
// if type is y.PlatformType I want to return y.PlatformType.DVL
// etc
default:
return null;
}
}
}
Is it possible to develop a method like this?
Thank in advance,
Since you know it's an Enum, the simplest thing would be to use Enum.TryParse:
public class Helper<T> where T : struct
{
public T GetPlatformType()
{
string platform = System.Configuration.ConfigurationManager.AppSettings["Platform"];
T value;
if (Enum.TryParse(platform, out value))
return value;
else
return default(T); // or throw, or something else reasonable
}
}
Note, I removed the Type parameter because I assumed it was given by T. Perhaps it would be better for you (depends on usage scenario) to make the method generic, and not the whole class - like this:
public class Helper
{
public T GetPlatformType<T>() where T : struct
{ ... }
}

C# Method to Return 1 of 3 Possible Enums

I have the three following enums:
public enum SensorTypeA{A1,A2,...,A12};
public enum SensorTypeB{B1,B2,...,B12};
public enum SensorTypeC{C1,C2,...,C12};
I am communicating with a sensor circuit via serial port and want to see which sensor is being used at location "x" so I created a method
public ???? GetSensorTypeAtLocation(int x)
{
...
// Send serial command and receive response.
string responseCommand = SendReceive(String.Format("SR,ML,{0},\r", x));
// Process response command string and return result.
return ???? (could be any of the 3 possible enums)
}
Is there a way I can return any of the possible enums? Cast to object? Better way?
Thanks!
EDIT
There are multiple sensors for each sensor type. I changed the enums to reflect this.
This looks like a job for Enum.TryParse().
public Enum GetSensorTypeAtLocation(int x)
{
...
// Send serial command and receive response.
string responseCommand = SendReceive(String.Format("SR,ML,{0},\r", x));
//Try to parse the response into a value from one of the enums;
//the first one that succeeds is our sensor type.
SensorTypeA typeAresult;
if(Enum.TryParse(responseCommand, typeAResult)) return typeAresult;
SensorTypeB typeBresult;
if(Enum.TryParse(responseCommand, typeBResult)) return typeBresult;
SensorTypeC typeCresult;
if(Enum.TryParse(responseCommand, typeCResult)) return typeCresult;
}
The problem will be that you cannot create overloads based on return type, and therefore you will not know exactly what the system will return (but the CLR will know at runtime, and you can interrogate the type of the return value to get a specific answer).
I would seriously consider an Enum SensorType containing A, B and C values. Then, the function can return a definite answer based on what type of response the sensor gave:
public SensorType GetSensorTypeAtLocation(int x)
{
...
// Send serial command and receive response.
string responseCommand = SendReceive(String.Format("SR,ML,{0},\r", x));
// Process response command string and return result.
SensorTypeA typeAresult;
if(Enum.TryParse(responseCommand, typeAResult)) return SensorType.A;
SensorTypeB typeBresult;
if(Enum.TryParse(responseCommand, typeBResult)) return SensorType.B;
SensorTypeC typeCresult;
if(Enum.TryParse(responseCommand, typeCResult)) return SensorType.C;
}
Now, you know from the return value itself, plain as day, the type of the sensor.
You can ignore the Enum part of the question completely because the root of the question is "Can a function return multiple types". The answer to this is "yes" but you'll have to return a higher level class, in this case Object and you'll need to do type checking after returning:
public enum SensorTypeA { A = 0 };
public enum SensorTypeB { B = 1 };
public enum SensorTypeC { C = 2 };
private object GetSensorTypeAtLocation()
{
return SensorTypeB.B;
}
private void YourMethod(object sender, EventArgs e)
{
object value = GetSensorTypeAtLocation();
if (value is SensorTypeA)
{
Console.WriteLine("A");
}
else if (value is SensorTypeB)
{
Console.WriteLine("B");
}
else if (value is SensorTypeC)
{
Console.WriteLine("C");
}
else
{
Console.WriteLine("Unknown");
}
}

convert an enum to another type of enum

I have an enum of for example 'Gender' (Male =0 , Female =1) and I have another enum from a service which has its own Gender enum (Male =0 , Female =1, Unknown =2)
My question is how can I write something quick and nice to convert from their enum to mine?
Given Enum1 value = ..., then if you mean by name:
Enum2 value2 = (Enum2) Enum.Parse(typeof(Enum2), value.ToString());
If you mean by numeric value, you can usually just cast:
Enum2 value2 = (Enum2)value;
(with the cast, you might want to use Enum.IsDefined to check for valid values, though)
Using an extension method works quite neatly, when using the two conversion methods suggested by Nate:
public static class TheirGenderExtensions
{
public static MyGender ToMyGender(this TheirGender value)
{
// insert switch statement here
}
}
public static class MyGenderExtensions
{
public static TheirGender ToTheirGender(this MyGender value)
{
// insert switch statement here
}
}
Obviously there's no need to use separate classes if you don't want to. My preference is to keep extension methods grouped by the classes/structures/enumerations they apply to.
Just cast one to int and then cast it to the other enum (considering that you want the mapping done based on value):
Gender2 gender2 = (Gender2)((int)gender1);
If we have:
enum Gender
{
M = 0,
F = 1,
U = 2
}
and
enum Gender2
{
Male = 0,
Female = 1,
Unknown = 2
}
We can safely do
var gender = Gender.M;
var gender2 = (Gender2)(int)gender;
Or even
var enumOfGender2Type = (Gender2)0;
If you want to cover the case where an enum on the right side of the '=' sign has more values than the enum on the left side - you will have to write your own method/dictionary to cover that as others suggested.
To be thorough I normally create a pair of functions, one that takes Enum 1 and returns Enum 2 and another that takes Enum 2 and returns Enum 1. Each consists of a case statement mapping inputs to outputs and the default case throws an exception with a message complaining about an unexpected value.
In this particular case you could take advantage of the fact that the integer values of Male and Female are the same, but I'd avoid that as it's hackish and subject to breakage if either enum changes in the future.
You could write a simple generic extension method like this
public static T ConvertTo<T>(this object value)
where T : struct,IConvertible
{
var sourceType = value.GetType();
if (!sourceType.IsEnum)
throw new ArgumentException("Source type is not enum");
if (!typeof(T).IsEnum)
throw new ArgumentException("Destination type is not enum");
return (T)Enum.Parse(typeof(T), value.ToString());
}
I wrote this answer because I believe there are fundamental issues with the majority of answers already provided, and the ones that are acceptable are incomplete.
Mapping by enum integer value
This approach is bad simply because it assumes that the integer values of both MyGender and TheirGender will always remain comparable. In practice, it is very rare that you can guarantee this even within a single project, let alone a separate service.
The approach we take should be something that can be used for other enum-mapping cases. We should never assume that one enum identically relates to another - especially when we may not have control over one or another.
Mapping by enum string value
This is a little better, as MyGender.Male will still convert to TheirGender.Male even if the integer representation is changed, but still not ideal.
I would discourage this approach as it assumes the name values will not change, and will always remain identical. Considering future enhancements, you cannot guarantee that this will be the case; consider if MyGender.NotKnown was added. It is likely that you would want this to map to TheirGender.Unknown, but this would not be supported.
Also, it is generally bad to assume that one enum equates to another by name, as this might not be the case in some contexts. As mentioned earlier, an ideal approach would work for other enum-mapping requirements.
Explicitly mapping enums
This approach explictly maps MyGender to TheirGender using a switch statement.
This is better as:
Covers the case where the underlying integer value changes.
Covers the case where the enum names changes (i.e. no assumptions - the developer will need to update the code to handle the scenario - good).
Handles cases where enum values cannot be mapped.
Handles cases where new enum values are added and cannot be mapped by default (again, no assumptions made - good).
Can easily be updated to support new enum values for either MyGender or TheirGender.
The same approach can be taken for all enum mapping requirements.
Assuming we have the following enums:
public enum MyGender
{
Male = 0,
Female = 1,
}
public enum TheirGender
{
Male = 0,
Female = 1,
Unknown = 2,
}
We can create the following function to "convert from their enum to mine":
public MyGender GetMyGender(TheirGender theirGender)
{
switch (theirGender)
{
case TheirGender.Male:
return MyGender.Male;
case TheirGender.Female:
return MyGender.Female;
default:
throw new InvalidEnumArgumentException(nameof(theirGender), (int)theirGender, typeof(TheirGender));
}
}
A previous answer suggested returning a nullable enum (TheirGender?) and returning null for any unmatched input. This is bad; null is not the same as an unknown mapping. If the input cannot be mapped, an exception should be thrown, else the method should be named more explictly to the behaviour:
public TheirGender? GetTheirGenderOrDefault(MyGender myGender)
{
switch (myGender)
{
case MyGender.Male:
return TheirGender.Male;
case MyGender.Female:
return TheirGender.Female;
default:
return default(TheirGender?);
}
}
Additional considerations
If it is likely that this method will be required more than once in various parts of the solution, you could consider creating an extension method for this:
public static class TheirGenderExtensions
{
public static MyGender GetMyGender(this TheirGender theirGender)
{
switch (theirGender)
{
case TheirGender.Male:
return MyGender.Male;
case TheirGender.Female:
return MyGender.Female;
default:
throw new InvalidEnumArgumentException(nameof(theirGender), (int)theirGender, typeof(TheirGender));
}
}
}
If you are using C#8, you can use the syntax for switch expressions and expression bodies to neaten up the code:
public static class TheirGenderExtensions
{
public static MyGender GetMyGender(this TheirGender theirGender)
=> theirGender switch
{
TheirGender.Male => MyGender.Male,
TheirGender.Female => MyGender.Female,
_ => throw new InvalidEnumArgumentException(nameof(theirGender), (int)theirGender, typeof(TheirGender))
};
}
If you will only ever be mapping the enums within a single class, then an extension method may be overkill. In this case, the method can be declared within the class itself.
Furthermore, if the mapping will only ever take place within a single method, then you can declare this as a local function:
public static void Main()
{
Console.WriteLine(GetMyGender(TheirGender.Male));
Console.WriteLine(GetMyGender(TheirGender.Female));
Console.WriteLine(GetMyGender(TheirGender.Unknown));
static MyGender GetMyGender(TheirGender theirGender)
=> theirGender switch
{
TheirGender.Male => MyGender.Male,
TheirGender.Female => MyGender.Female,
_ => throw new InvalidEnumArgumentException(nameof(theirGender), (int)theirGender, typeof(TheirGender))
};
}
Here's a dotnet fiddle link with the above example.
tl;dr:
Do not:
Map enums by integer value
Map enums by name
Do:
Map enums explicitly using a switch statement
Throw an exception when a value cannot be mapped rather than returning null
Consider using extension methods
you could write a simple function like the following:
public static MyGender ConvertTo(TheirGender theirGender)
{
switch(theirGender)
{
case TheirGender.Male:
break;//return male
case TheirGender.Female:
break;//return female
case TheirGender.Unknown:
break;//return whatever
}
}
Here's an extension method version if anyone is interested
public static TEnum ConvertEnum<TEnum >(this Enum source)
{
return (TEnum)Enum.Parse(typeof(TEnum), source.ToString(), true);
}
// Usage
NewEnumType newEnum = oldEnumVar.ConvertEnum<NewEnumType>();
In case when the enum members have different values, you can apply something like this:
public static MyGender? MapToMyGender(this Gender gender)
{
return gender switch
{
Gender.Male => MyGender.Male,
Gender.Female => MyGender.Female,
Gender.Unknown => null,
_ => throw new InvalidEnumArgumentException($"Invalid gender: {gender}")
};
}
Then you can call: var myGender = gender.MapToMyGender();
Update:
This previous code works only with C# 8.
For older versions of C#, you can use the switch statement instead of the switch expression:
public static MyGender? MapToMyGender(this Gender gender)
{
switch (gender)
{
case Gender.Male:
return MyGender.Male;
case Gender.Female:
return MyGender.Female;
case Gender.Unknown:
return null;
default:
throw new InvalidEnumArgumentException($"Invalid gender: {gender}")
};
}
Based on Justin's answer above I came up with this:
/// <summary>
/// Converts Enum Value to different Enum Value (by Value Name) See https://stackoverflow.com/a/31993512/6500501.
/// </summary>
/// <typeparam name="TEnum">The type of the enum to convert to.</typeparam>
/// <param name="source">The source enum to convert from.</param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public static TEnum ConvertTo<TEnum>(this Enum source)
{
try
{
return (TEnum) Enum.Parse(typeof(TEnum), source.ToString(), ignoreCase: true);
}
catch (ArgumentException aex)
{
throw new InvalidOperationException
(
$"Could not convert {source.GetType().ToString()} [{source.ToString()}] to {typeof(TEnum).ToString()}", aex
);
}
}
public static TEnum ConvertByName<TEnum>(this Enum source, bool ignoreCase = false) where TEnum : struct
{
// if limited by lack of generic enum constraint
if (!typeof(TEnum).IsEnum)
{
throw new InvalidOperationException("enumeration type required.");
}
TEnum result;
if (!Enum.TryParse(source.ToString(), ignoreCase, out result))
{
throw new Exception("conversion failure.");
}
return result;
}
I wrote a set extension methods a while back that work for several different kinds of Enums. One in particular works for what you are trying to accomplish and handles Enums with the FlagsAttribute as well as Enums with different underlying types.
public static tEnum SetFlags<tEnum>(this Enum e, tEnum flags, bool set, bool typeCheck = true) where tEnum : IComparable
{
if (typeCheck)
{
if (e.GetType() != flags.GetType())
throw new ArgumentException("Argument is not the same type as this instance.", "flags");
}
var flagsUnderlyingType = Enum.GetUnderlyingType(typeof(tEnum));
var firstNum = Convert.ToUInt32(e);
var secondNum = Convert.ToUInt32(flags);
if (set)
firstNum |= secondNum;
else
firstNum &= ~secondNum;
var newValue = (tEnum)Convert.ChangeType(firstNum, flagsUnderlyingType);
if (!typeCheck)
{
var values = Enum.GetValues(typeof(tEnum));
var lastValue = (tEnum)values.GetValue(values.Length - 1);
if (newValue.CompareTo(lastValue) > 0)
return lastValue;
}
return newValue;
}
From there you can add other more specific extension methods.
public static tEnum AddFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable
{
SetFlags(e, flags, true);
}
public static tEnum RemoveFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable
{
SetFlags(e, flags, false);
}
This one will change types of Enums like you are trying to do.
public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable
{
return SetFlags(e, default(tEnum), true, false);
}
Be warned, though, that you CAN convert between any Enum and any other Enum using this method, even those that do not have flags. For example:
public enum Turtle
{
None = 0,
Pink,
Green,
Blue,
Black,
Yellow
}
[Flags]
public enum WriteAccess : short
{
None = 0,
Read = 1,
Write = 2,
ReadWrite = 3
}
static void Main(string[] args)
{
WriteAccess access = WriteAccess.ReadWrite;
Turtle turtle = access.ChangeType<Turtle>();
}
The variable turtle will have a value of Turtle.Blue.
However, there is safety from undefined Enum values using this method. For instance:
static void Main(string[] args)
{
Turtle turtle = Turtle.Yellow;
WriteAccess access = turtle.ChangeType<WriteAccess>();
}
In this case, access will be set to WriteAccess.ReadWrite, since the WriteAccess Enum has a maximum value of 3.
Another side effect of mixing Enums with the FlagsAttribute and those without it is that the conversion process will not result in a 1 to 1 match between their values.
public enum Letters
{
None = 0,
A,
B,
C,
D,
E,
F,
G,
H
}
[Flags]
public enum Flavors
{
None = 0,
Cherry = 1,
Grape = 2,
Orange = 4,
Peach = 8
}
static void Main(string[] args)
{
Flavors flavors = Flavors.Peach;
Letters letters = flavors.ChangeType<Letters>();
}
In this case, letters will have a value of Letters.H instead of Letters.D, since the backing value of Flavors.Peach is 8. Also, a conversion from Flavors.Cherry | Flavors.Grape to Letters would yield Letters.C, which can seem unintuitive.
I know that's an old question and have a lot of answers, However I find that using a switch statement as in the accepted answer is somewhat cumbersome, so here are my 2 cents:
My personal favorite method is to use a dictionary, where the key is the source enum and the value is the target enum - so in the case presented on the question my code would look like this:
var genderTranslator = new Dictionary<TheirGender, MyGender>();
genderTranslator.Add(TheirGender.Male, MyGender.Male);
genderTranslator.Add(TheirGender.Female, MyGender.Female);
genderTranslator.Add(TheirGender.Unknown, MyGender.Unknown);
// translate their to mine
var myValue = genderTranslator[TheirValue];
// translate mine to their
var TheirValue = genderTranslator .FirstOrDefault(x => x.Value == myValue).Key;;
Of course, this can be wrapped in a static class and be used as an extension methods:
public static class EnumTranslator
{
private static Dictionary<TheirGender, MyGender> GenderTranslator = InitializeGenderTranslator();
private static Dictionary<TheirGender, MyGender> InitializeGenderTranslator()
{
var translator = new Dictionary<TheirGender, MyGender>();
translator.Add(TheirGender.Male, MyGender.Male);
translator.Add(TheirGender.Female, MyGender.Female);
translator.Add(TheirGender.Unknown, MyGender.Unknown);
return translator;
}
public static MyGender Translate(this TheirGender theirValue)
{
return GenderTranslator[theirValue];
}
public static TheirGender Translate(this MyGender myValue)
{
return GenderTranslator.FirstOrDefault(x => x.Value == myValue).Key;
}
}
You can use ToString() to convert the first enum to its name, and then Enum.Parse() to convert the string back to the other Enum. This will throw an exception if the value is not supported by the destination enum (i.e. for an "Unknown" value)
For grins you can do this
public enum TestNum {
{
[EnumConvert( NewType.AType )]
Test1,
[EnumConvert( NewType.BType )]
Test2
}
public enum NewType {
AType,
BType
}
public static class EnumExtensions {
public static Enum GetEnum(this Enum value ) {
var attribute = (EnumConvertAttribute)value.GetType()
.GetField( value.ToString() )
.GetCustomAttribute( false )
.Where( a => a is EnumConvertAttribute
.FirstOrDefault();
if( attribute == null ) {
throw new ArgumentNullException();
}
try {
return attribute.TargetEnum;
} catch ( Exception ex ) {
throw new InvalidArgumentException();
}
}
}
public class EnumConvertAttribute : Attribute {
public Enum TargetEnum;
public EnumConvertAttribute( object e ) {
TargetEnum = (Enum)e;
}
}
call:
var t1 = TestNum.Test2;
var t2 = t1.GetEnum();
t2 = NewType.BType;
It works, assuming you don't mind boxing. Converting enums a lot is not good practice anyways. You do get strong typing, you don't have 2 methods for conversions to create a bug eventually when maintaining, and your not praying that the string or int comparisons don't fail.
Enum1 var1;
Enum2 var2;
var2 = Enum2.fromValue(var1.getValue())
public enum Enum2 {
FEMALE("FEMALE"),
MALE("MALE")
private String value;
public static Enum2 fromValue(String value) {
for (Enum2 b : Enum2.values()) {
if (b.value.equals(value)) {
return b;
}
}
throw new IllegalArgumentException("Unexpected value '" + value + "'");
}
}

Categories

Resources