Is it possible to define an implicit conversion of enums in c#?
something that could achieve this?
public enum MyEnum
{
one = 1, two = 2
}
MyEnum number = MyEnum.one;
long i = number;
If not, why not?
There is a solution. Consider the following:
public sealed class AccountStatus
{
public static readonly AccountStatus Open = new AccountStatus(1);
public static readonly AccountStatus Closed = new AccountStatus(2);
public static readonly SortedList<byte, AccountStatus> Values = new SortedList<byte, AccountStatus>();
private readonly byte Value;
private AccountStatus(byte value)
{
this.Value = value;
Values.Add(value, this);
}
public static implicit operator AccountStatus(byte value)
{
return Values[value];
}
public static implicit operator byte(AccountStatus value)
{
return value.Value;
}
}
The above offers implicit conversion:
AccountStatus openedAccount = 1; // Works
byte openedValue = AccountStatus.Open; // Works
This is a fair bit more work than declaring a normal enum (though you can refactor some of the above into a common generic base class). You can go even further by having the base class implement IComparable & IEquatable, as well as adding methods to return the value of DescriptionAttributes, declared names, etc, etc.
I wrote a base class (RichEnum<>) to handle most fo the grunt work, which eases the above declaration of enums down to:
public sealed class AccountStatus : RichEnum<byte, AccountStatus>
{
public static readonly AccountStatus Open = new AccountStatus(1);
public static readonly AccountStatus Closed = new AccountStatus(2);
private AccountStatus(byte value) : base (value)
{
}
public static implicit operator AccountStatus(byte value)
{
return Convert(value);
}
}
The base class (RichEnum) is listed below.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;
namespace Ethica
{
using Reflection;
using Text;
[DebuggerDisplay("{Value} ({Name})")]
public abstract class RichEnum<TValue, TDerived>
: IEquatable<TDerived>,
IComparable<TDerived>,
IComparable, IComparer<TDerived>
where TValue : struct , IComparable<TValue>, IEquatable<TValue>
where TDerived : RichEnum<TValue, TDerived>
{
#region Backing Fields
/// <summary>
/// The value of the enum item
/// </summary>
public readonly TValue Value;
/// <summary>
/// The public field name, determined from reflection
/// </summary>
private string _name;
/// <summary>
/// The DescriptionAttribute, if any, linked to the declaring field
/// </summary>
private DescriptionAttribute _descriptionAttribute;
/// <summary>
/// Reverse lookup to convert values back to local instances
/// </summary>
private static SortedList<TValue, TDerived> _values;
private static bool _isInitialized;
#endregion
#region Constructors
protected RichEnum(TValue value)
{
if (_values == null)
_values = new SortedList<TValue, TDerived>();
this.Value = value;
_values.Add(value, (TDerived)this);
}
#endregion
#region Properties
public string Name
{
get
{
CheckInitialized();
return _name;
}
}
public string Description
{
get
{
CheckInitialized();
if (_descriptionAttribute != null)
return _descriptionAttribute.Description;
return _name;
}
}
#endregion
#region Initialization
private static void CheckInitialized()
{
if (!_isInitialized)
{
ResourceManager _resources = new ResourceManager(typeof(TDerived).Name, typeof(TDerived).Assembly);
var fields = typeof(TDerived)
.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public)
.Where(t => t.FieldType == typeof(TDerived));
foreach (var field in fields)
{
TDerived instance = (TDerived)field.GetValue(null);
instance._name = field.Name;
instance._descriptionAttribute = field.GetAttribute<DescriptionAttribute>();
var displayName = field.Name.ToPhrase();
}
_isInitialized = true;
}
}
#endregion
#region Conversion and Equality
public static TDerived Convert(TValue value)
{
return _values[value];
}
public static bool TryConvert(TValue value, out TDerived result)
{
return _values.TryGetValue(value, out result);
}
public static implicit operator TValue(RichEnum<TValue, TDerived> value)
{
return value.Value;
}
public static implicit operator RichEnum<TValue, TDerived>(TValue value)
{
return _values[value];
}
public static implicit operator TDerived(RichEnum<TValue, TDerived> value)
{
return value;
}
public override string ToString()
{
return _name;
}
#endregion
#region IEquatable<TDerived> Members
public override bool Equals(object obj)
{
if (obj != null)
{
if (obj is TValue)
return Value.Equals((TValue)obj);
if (obj is TDerived)
return Value.Equals(((TDerived)obj).Value);
}
return false;
}
bool IEquatable<TDerived>.Equals(TDerived other)
{
return Value.Equals(other.Value);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
#endregion
#region IComparable Members
int IComparable<TDerived>.CompareTo(TDerived other)
{
return Value.CompareTo(other.Value);
}
int IComparable.CompareTo(object obj)
{
if (obj != null)
{
if (obj is TValue)
return Value.CompareTo((TValue)obj);
if (obj is TDerived)
return Value.CompareTo(((TDerived)obj).Value);
}
return -1;
}
int IComparer<TDerived>.Compare(TDerived x, TDerived y)
{
return (x == null) ? -1 :
(y == null) ? 1 :
x.Value.CompareTo(y.Value);
}
#endregion
public static IEnumerable<TDerived> Values
{
get
{
return _values.Values;
}
}
public static TDerived Parse(string name)
{
foreach (TDerived value in _values.Values)
if (0 == string.Compare(value.Name, name, true) || 0 == string.Compare(value.DisplayName, name, true))
return value;
return null;
}
}
}
You can't do implict conversions (except for zero), and you can't write your own instance methods - however, you can probably write your own extension methods:
public enum MyEnum { A, B, C }
public static class MyEnumExt
{
public static int Value(this MyEnum foo) { return (int)foo; }
static void Main()
{
MyEnum val = MyEnum.A;
int i = val.Value();
}
}
This doesn't give you a lot, though (compared to just doing an explicit cast).
One of the main times I've seen people want this is for doing [Flags] manipulation via generics - i.e. a bool IsFlagSet<T>(T value, T flag); method. Unfortunately, C# 3.0 doesn't support operators on generics, but you can get around this using things like this, which make operators fully available with generics.
struct PseudoEnum
{
public const int
INPT = 0,
CTXT = 1,
OUTP = 2;
};
// ...
var arr = new String[3];
arr[PseudoEnum.CTXT] = "can";
arr[PseudoEnum.INPT] = "use";
arr[PseudoEnum.CTXT] = "as";
arr[PseudoEnum.CTXT] = "array";
arr[PseudoEnum.OUTP] = "index";
I adapted Mark's excellent RichEnum generic baseclass.
Fixing
a number of compilation problems due to missing bits from his libraries (notably: the resource dependent display names weren't completely removed; they are now)
initialization wasn't perfect: if the first thing you did was access the static .Values property from the base class, you'd get a NPE. Fixed this by forcing the base class to curiously-recursively (CRTP) force the static construction of TDerived just in time during CheckInitialized
finally moved CheckInitialized logic into a static constructor (to avoid the penalty of checking each time, the race condition on multithreaded initialization; perhaps this was an impossibility solved by my bullet 1.?)
Kudos to Mark for the splendid idea + implementation, here's to you all:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;
namespace NMatrix
{
[DebuggerDisplay("{Value} ({Name})")]
public abstract class RichEnum<TValue, TDerived>
: IEquatable<TDerived>,
IComparable<TDerived>,
IComparable, IComparer<TDerived>
where TValue : struct, IComparable<TValue>, IEquatable<TValue>
where TDerived : RichEnum<TValue, TDerived>
{
#region Backing Fields
/// <summary>
/// The value of the enum item
/// </summary>
public readonly TValue Value;
/// <summary>
/// The public field name, determined from reflection
/// </summary>
private string _name;
/// <summary>
/// The DescriptionAttribute, if any, linked to the declaring field
/// </summary>
private DescriptionAttribute _descriptionAttribute;
/// <summary>
/// Reverse lookup to convert values back to local instances
/// </summary>
private static readonly SortedList<TValue, TDerived> _values = new SortedList<TValue, TDerived>();
#endregion
#region Constructors
protected RichEnum(TValue value)
{
this.Value = value;
_values.Add(value, (TDerived)this);
}
#endregion
#region Properties
public string Name
{
get
{
return _name;
}
}
public string Description
{
get
{
if (_descriptionAttribute != null)
return _descriptionAttribute.Description;
return _name;
}
}
#endregion
#region Initialization
static RichEnum()
{
var fields = typeof(TDerived)
.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public)
.Where(t => t.FieldType == typeof(TDerived));
foreach (var field in fields)
{
/*var dummy =*/ field.GetValue(null); // forces static initializer to run for TDerived
TDerived instance = (TDerived)field.GetValue(null);
instance._name = field.Name;
instance._descriptionAttribute = field.GetCustomAttributes(true).OfType<DescriptionAttribute>().FirstOrDefault();
}
}
#endregion
#region Conversion and Equality
public static TDerived Convert(TValue value)
{
return _values[value];
}
public static bool TryConvert(TValue value, out TDerived result)
{
return _values.TryGetValue(value, out result);
}
public static implicit operator TValue(RichEnum<TValue, TDerived> value)
{
return value.Value;
}
public static implicit operator RichEnum<TValue, TDerived>(TValue value)
{
return _values[value];
}
public static implicit operator TDerived(RichEnum<TValue, TDerived> value)
{
return value;
}
public override string ToString()
{
return _name;
}
#endregion
#region IEquatable<TDerived> Members
public override bool Equals(object obj)
{
if (obj != null)
{
if (obj is TValue)
return Value.Equals((TValue)obj);
if (obj is TDerived)
return Value.Equals(((TDerived)obj).Value);
}
return false;
}
bool IEquatable<TDerived>.Equals(TDerived other)
{
return Value.Equals(other.Value);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
#endregion
#region IComparable Members
int IComparable<TDerived>.CompareTo(TDerived other)
{
return Value.CompareTo(other.Value);
}
int IComparable.CompareTo(object obj)
{
if (obj != null)
{
if (obj is TValue)
return Value.CompareTo((TValue)obj);
if (obj is TDerived)
return Value.CompareTo(((TDerived)obj).Value);
}
return -1;
}
int IComparer<TDerived>.Compare(TDerived x, TDerived y)
{
return (x == null) ? -1 :
(y == null) ? 1 :
x.Value.CompareTo(y.Value);
}
#endregion
public static IEnumerable<TDerived> Values
{
get
{
return _values.Values;
}
}
public static TDerived Parse(string name)
{
foreach (TDerived value in Values)
if (0 == string.Compare(value.Name, name, true))
return value;
return null;
}
}
}
A sample of usage that I ran on mono:
using System.ComponentModel;
using System;
namespace NMatrix
{
public sealed class MyEnum : RichEnum<int, MyEnum>
{
[Description("aap")] public static readonly MyEnum my_aap = new MyEnum(63000);
[Description("noot")] public static readonly MyEnum my_noot = new MyEnum(63001);
[Description("mies")] public static readonly MyEnum my_mies = new MyEnum(63002);
private MyEnum(int value) : base (value) { }
public static implicit operator MyEnum(int value) { return Convert(value); }
}
public static class Program
{
public static void Main(string[] args)
{
foreach (var enumvalue in MyEnum.Values)
Console.WriteLine("MyEnum {0}: {1} ({2})", (int) enumvalue, enumvalue, enumvalue.Description);
}
}
}
Producing the output
[mono] ~/custom/demo # gmcs test.cs richenum.cs && ./test.exe
MyEnum 63000: my_aap (aap)
MyEnum 63001: my_noot (noot)
MyEnum 63002: my_mies (mies)
Note: mono 2.6.7 requires an extra explicit cast that is not required when using mono 2.8.2...
You cannot declare implicit conversions on enum types, because they can't define methods. The C# implicit keyword compiles into a method starting with 'op_', and it wouldn't work in this case.
You probably could, but not for the enum (you can't add a method to it). You could add an implicit conversion to you own class to allow an enum to be converted to it,
public class MyClass {
public static implicit operator MyClass ( MyEnum input ) {
//...
}
}
MyClass m = MyEnum.One;
The question would be why?
In general .Net avoids (and you should too) any implicit conversion where data can be lost.
enums are largely useless for me because of this, OP.
I end up doing pic-related all the time:
the simple solution
classic example problem is the VirtualKey set for detecting keypresses.
enum VKeys : ushort
{
a = 1,
b = 2,
c = 3
}
// the goal is to index the array using predefined constants
int[] array = new int[500];
var x = array[VKeys.VK_LSHIFT];
problem here is you can't index the array with the enum because it can't implicitly convert enum to ushort (even though we even based the enum on ushort)
in this specific context, enums are obsoleted by the following datastructure
. . . .
public static class VKeys
{
public const ushort
a = 1,
b = 2,
c = 3;
}
I found even easier solution taken from here https://codereview.stackexchange.com/questions/7566/enum-vs-int-wrapper-struct I pasted the code below from that link just in case it does not work in the future.
struct Day
{
readonly int day;
public static readonly Day Monday = 0;
public static readonly Day Tuesday = 1;
public static readonly Day Wednesday = 2;
public static readonly Day Thursday = 3;
public static readonly Day Friday = 4;
public static readonly Day Saturday = 5;
public static readonly Day Sunday = 6;
private Day(int day)
{
this.day = day;
}
public static implicit operator int(Day value)
{
return value.day;
}
public static implicit operator Day(int value)
{
return new Day(value);
}
}
I created this utility to help me convert an Enum to PrimitiveEnum and PrimitiveEnum to byte, sbyte, short, ushort, int, uint, long, or ulong.
So, this technically converts any enum to any its primitive value.
public enum MyEnum
{
one = 1, two = 2
}
PrimitiveEnum number = MyEnum.one;
long i = number;
See commit at https://github.com/McKabue/McKabue.Extentions.Utility/blob/master/src/McKabue.Extentions.Utility/Enums/PrimitiveEnum.cs
using System;
namespace McKabue.Extentions.Utility.Enums
{
/// <summary>
/// <see href="https://stackoverflow.com/q/261663/3563013">
/// Can we define implicit conversions of enums in c#?
/// </see>
/// </summary>
public struct PrimitiveEnum
{
private Enum _enum;
public PrimitiveEnum(Enum _enum)
{
this._enum = _enum;
}
public Enum Enum => _enum;
public static implicit operator PrimitiveEnum(Enum _enum)
{
return new PrimitiveEnum(_enum);
}
public static implicit operator Enum(PrimitiveEnum primitiveEnum)
{
return primitiveEnum.Enum;
}
public static implicit operator byte(PrimitiveEnum primitiveEnum)
{
return Convert.ToByte(primitiveEnum.Enum);
}
public static implicit operator sbyte(PrimitiveEnum primitiveEnum)
{
return Convert.ToSByte(primitiveEnum.Enum);
}
public static implicit operator short(PrimitiveEnum primitiveEnum)
{
return Convert.ToInt16(primitiveEnum.Enum);
}
public static implicit operator ushort(PrimitiveEnum primitiveEnum)
{
return Convert.ToUInt16(primitiveEnum.Enum);
}
public static implicit operator int(PrimitiveEnum primitiveEnum)
{
return Convert.ToInt32(primitiveEnum.Enum);
}
public static implicit operator uint(PrimitiveEnum primitiveEnum)
{
return Convert.ToUInt32(primitiveEnum.Enum);
}
public static implicit operator long(PrimitiveEnum primitiveEnum)
{
return Convert.ToInt64(primitiveEnum.Enum);
}
public static implicit operator ulong(PrimitiveEnum primitiveEnum)
{
return Convert.ToUInt64(primitiveEnum.Enum);
}
}
}
If you define the base of the enum as a long then you can perform explicit conversion. I don't know if you can use implicit conversions as enums cannot have methods defined on them.
public enum MyEnum : long
{
one = 1,
two = 2,
}
MyEnum number = MyEnum.one;
long i = (long)number;
Also, be aware with this that an uninitalised enumeration will default to the 0 value, or the first item - so in the situation above it would probably be best to define zero = 0 as well.
I've worked around an issue with sehe's answer when running the code on MS .net (non-Mono). For me specifically the issue occurred on .net 4.5.1 but other versions seem affected, too.
The issue
accessing a public static TDervied MyEnumValue by reflection (via FieldInfo.GetValue(null) does not initialize said field.
The workaround
Instead of assigning names to TDerived instances upon the static initializer of RichEnum<TValue, TDerived> this is done lazily on first access of TDerived.Name. The code:
public abstract class RichEnum<TValue, TDerived> : EquatableBase<TDerived>
where TValue : struct, IComparable<TValue>, IEquatable<TValue>
where TDerived : RichEnum<TValue, TDerived>
{
// Enforcing that the field Name (´SomeEnum.SomeEnumValue´) is the same as its
// instances ´SomeEnum.Name´ is done by the static initializer of this class.
// Explanation of initialization sequence:
// 1. the static initializer of ´RichEnum<TValue, TDerived>´ reflects TDervied and
// creates a list of all ´public static TDervied´ fields:
// ´EnumInstanceToNameMapping´
// 2. the static initializer of ´TDerive´d assigns values to these fields
// 3. The user is now able to access the values of a field.
// Upon first access of ´TDervied.Name´ we search the list
// ´EnumInstanceToNameMapping´ (created at step 1) for the field that holds
// ´this´ instance of ´TDerived´.
// We then get the Name for ´this´ from the FieldInfo
private static readonly IReadOnlyCollection<EnumInstanceReflectionInfo>
EnumInstanceToNameMapping =
typeof(TDerived)
.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public)
.Where(t => t.FieldType == typeof(TDerived))
.Select(fieldInfo => new EnumInstanceReflectionInfo(fieldInfo))
.ToList();
private static readonly SortedList<TValue, TDerived> Values =
new SortedList<TValue, TDerived>();
public readonly TValue Value;
private readonly Lazy<string> _name;
protected RichEnum(TValue value)
{
Value = value;
// SortedList doesn't allow duplicates so we don't need to do
// duplicate checking ourselves
Values.Add(value, (TDerived)this);
_name = new Lazy<string>(
() => EnumInstanceToNameMapping
.First(x => ReferenceEquals(this, x.Instance))
.Name);
}
public string Name
{
get { return _name.Value; }
}
public static implicit operator TValue(RichEnum<TValue, TDerived> richEnum)
{
return richEnum.Value;
}
public static TDerived Convert(TValue value)
{
return Values[value];
}
protected override bool Equals(TDerived other)
{
return Value.Equals(other.Value);
}
protected override int ComputeHashCode()
{
return Value.GetHashCode();
}
private class EnumInstanceReflectionInfo
{
private readonly FieldInfo _field;
private readonly Lazy<TDerived> _instance;
public EnumInstanceReflectionInfo(FieldInfo field)
{
_field = field;
_instance = new Lazy<TDerived>(() => (TDerived)field.GetValue(null));
}
public TDerived Instance
{
get { return _instance.Value; }
}
public string Name { get { return _field.Name; } }
}
}
which - in my case - is based upon EquatableBase<T>:
public abstract class EquatableBase<T>
where T : class
{
public override bool Equals(object obj)
{
if (this == obj)
{
return true;
}
T other = obj as T;
if (other == null)
{
return false;
}
return Equals(other);
}
protected abstract bool Equals(T other);
public override int GetHashCode()
{
unchecked
{
return ComputeHashCode();
}
}
protected abstract int ComputeHashCode();
}
Note
The above code does not incorporate all features of Mark's original answer!
Thanks
Thanks to Mark for providing his RichEnum implementation and thanks to sehe for providing some improvements!
Here's a different flavour based on adminSoftDK's answer.
/// <summary>
/// Based on https://datatracker.ietf.org/doc/html/rfc4346#appendix-A.1
/// </summary>
[DebuggerDisplay("{_value}")]
public struct HandshakeContentType
{
#region Types
public const byte ChangeCipher = 0x14;
public const byte Alert = 0x15;
public const byte Handshake = 0x16;
public const byte ApplicationData = 0x17;
#endregion
byte _value;
private HandshakeContentType(byte value)
{
_value = value;
switch (_value)
{
case ChangeCipher:
case Alert:
case Handshake:
case ApplicationData:
break;
default:
throw new InvalidOperationException($"An invalid handshake content type (${value}) was provided.");
}
}
#region Methods
public static implicit operator byte(HandshakeContentType type) => type._value;
public static implicit operator HandshakeContentType(byte b) => new HandshakeContentType(b);
#endregion
}
This allows you to use this struct with switch statements which I think is pretty awesome.
#BatteryBackupUnit
Hey this sounds like a cool solution but could you explain this part here?
Since im getting with .NET 4.7.2 an "InvalidCastException" out of this sadly :/
_name = new Lazy<string>(
() => EnumInstanceToNameMapping
.First(x => ReferenceEquals(this, x.Instance))
.Name);
I dont know why, i have created a derived type of the RichEnum and initialized as everything u did in the example but i getthis annyoingg exception..
Would be glad of some help to this since i like this approach alot tbh.
I don't have enough rep to add a comment, but I was inspired by the 'struct' comment here:
https://stackoverflow.com/a/39141171/12135042
Here is how I did it:
public enum DaysOfWeek
{
Sunday = 0,
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 7,
}
public struct Weekends
{
private Weekends(DaysOfWeek day){ Day = day; }
public readonly DaysOfWeek Day;
public static Weekends Sunday = new(DaysOfWeek.Sunday);
public static Weekends Saturday = new(DaysOfWeek.Saturday);
public static implicit operator DaysOfWeek(Weekends value) => value.Mode;
}
I feel this gets the best of both worlds here, since you get your super enum, and easily accessible structs that are statically accessibly acting as subsets of the superenum.
Introducing implicit conversions for enum types would break type safety, so I'd not recommend to do that. Why would you want to do that? The only use case for this I've seen is when you want to put the enum values into a structure with a pre-defined layout. But even then, you can use the enum type in the structure and just tell the Marshaller what he should do with this.
I want to write a generic class that accepts enumerations. Since this class is intended to implement some interfaces, the main aim is to be able to treat enumerations as other objects implementing those interfaces(e.g. for list extensions, etc). Hence, for a sample enum
public enum QEnum : int
{
xlNoValue = 0,
xlSomeValue = 1
}
public static class QEnumExtensions
{
public static string toString(this QEnum xThis)
{
...
}
public static QEnum toEnum(this string xThis)
{
...
}
}
I would like to declare a generic class such as
public class QEnumHolder<T> where T : struct, IConvertible
{
private T mxVal = default(T);
public QEnumHolder()
{
if (!typeof(T).IsEnum) throw new NotSupportedException();
}
public QEnumHolder(T xVal)
{
if (!typeof(T).IsEnum) throw new NotSupportedException();
mxVal = xVal;
}
static public implicit operator QEnumHolder<T>(T xVal)
{
return new QEnumHolder<T>(xVal);
}
static public implicit operator T(QEnumHolder<T> xVal)
{
return (T)xVal.mxVal;
}
public string toString()
{
if (mxVal is QEnum) return ((QEnum)Convert.ToInt32(mxVal)).toString();
...
}
public void fromString(string xString)
{
if (mxVal is QEnum)
mxVal = (???)xString.toEnum(); // problem
}
}
All of the enumerations that we use implement
toString() function which returns a "nice" string that can go into comboBoxes, etc
conversion of string to enumeration, as above
hence the structure of toString/toEnum is pretty much given. The problem is with the last code line marked "problem". I have no idea how to tell the compiler that in this branch, the return type of toEnum() and T will be the same.
I tried to circumvent the problem by declaring mxVal as int and using Convert.ToInt32 everywhere. However, then I run into problem in the operator T where the compiler has objections against converting int to a T (the compiler can't know that T will be enum, hence I can't use none of the "int to enum conversion" discussions here on SO).
A better design would be to use some naming convention, put all your enum extension methods in one and the same static class, and bind these functions inside your holder class static constructor. Something like this:
public static partial class MyEnumExtensions
{
public static MyEnumHolder<T> ToHolder<T>(this T source)
where T : struct, IConvertible
{
return new MyEnumHolder<T>(source);
}
}
public class MyEnumHolder<T> where T : struct, IConvertible
{
static readonly Func<T, string> toStringFunc;
static readonly Func<string, T> toEnumFunc;
static MyEnumHolder()
{
if (!typeof(T).IsEnum) throw new NotSupportedException();
// Use your naming conventions
var name = typeof(T).Name;
toStringFunc = (Func<T, string>)Delegate.CreateDelegate(typeof(Func<T, string>),
typeof(MyEnumExtensions).GetMethod("toString", new[] { typeof(T) }));
toEnumFunc = (Func<string, T>)Delegate.CreateDelegate(typeof(Func<string, T>),
typeof(MyEnumExtensions).GetMethod("to" + name, new[] { typeof(string) }));
}
private T value;
public MyEnumHolder() { value = default(T); }
public MyEnumHolder(T value) { this.value = value; }
static public implicit operator MyEnumHolder<T>(T x) { return new MyEnumHolder<T>(x); }
static public implicit operator T(MyEnumHolder<T> x) { return x.value; }
public string toString()
{
return toStringFunc(value);
}
public void fromString(string xString)
{
value = toEnumFunc(xString);
}
}
Sample enum definitions (could be in separate files, but must be inside the same project):
public enum MyEnumA { A1, A2, A3 }
partial class MyEnumExtensions
{
public static string toString(this MyEnumA x)
{
//...
return x.ToString();
}
public static MyEnumA toMyEnumA(this string x)
{
//...
return (MyEnumA)Enum.Parse(typeof(MyEnumA), x);
}
}
and
public enum MyEnumB { B1, B2, B3 }
partial class MyEnumExtensions
{
public static string toString(this MyEnumB x)
{
//...
return x.ToString();
}
public static MyEnumB toMyEnumB(this string x)
{
//...
return (MyEnumB)Enum.Parse(typeof(MyEnumB), x);
}
}
test:
var a = MyEnumA.A1.ToHolder();
var sA = a.toString();
a.fromString("A2");
var b = MyEnumB.B2.ToHolder();
var sB = b.toString();
b.fromString("B1");
mxVal = (T)(object)xString.toEnum();
I use a 3rd party application for output. There are several int properties and I would like to handle the different properties' int values via enum.
Property1 could be 0,1,2
Property2 could be 0,1
Property3 could be 1,2
I think I should have enum inheritance which is not option in c#.
So I solved it by using classes (I'm using Tono Nam's answer from another topic to this end: https://stackoverflow.com/a/23430174/4273304).
public class MyEnum : IEquatable<MyEnum>
{
public static readonly MyEnum Undefined = new MyEnum(-1, "Undefined");
public int Value { get; private set; }
public string Name { get; private set; }
protected MyEnum(int value, string name)
{
this.Value = value;
this.Name = name;
}
public bool Equals(MyEnum b)
{
return this.Name == b.Name && this.Value == b.Value;
}
public override string ToString()
{
return this.Name;
}
public static T Parse<T>(int value)
{
object obj;
Type t_type = typeof(T);
var fiList = t_type.GetFields(BindingFlags.Public | BindingFlags.Static).Where(f => f.FieldType == typeof(T)).ToArray();
foreach(FieldInfo en in fiList)
{
object tmp = en.GetValue(null);
if (((MyEnum)tmp).Value == value)
return (T)tmp;
}
obj = MyEnum.Undefined;
return (T)obj;
}
}
public class MyEnumChild1 : MyEnum
{
public static readonly MyEnumChild1 A = new MyEnumChild1(0, "A");
public static readonly MyEnumChild1 B = new MyEnumChild1(1, "B");
private MyEnumChild1(int value, string name)
: base(value, name)
{
}
}
public class MyEnumChild2 : MyEnum
{
public static readonly MyEnumChild2 A = new MyEnumChild2(0, "A");
public static readonly MyEnumChild2 C = new MyEnumChild2(1, "C");
private MyEnumChild2(int value, string name)
: base(value, name)
{
}
}
public class MyEnumChild3 : MyEnum
{
public static readonly MyEnumChild3 D = new MyEnumChild3(0, "D");
public static readonly MyEnumChild3 E = new MyEnumChild3(1, "E");
private MyEnumChild3(int value, string name)
: base(value, name)
{
}
}
This solution serves my purposes, but I dont know how to cast an int to MyEnumChild1.
I created a parser method:
MyEnumChild1 MEC1 = MyEnum.Parse <MyEnumChild1>(1);
It seems to work fine, MEC1 is MyEnumChild1.B now, but I'm not sure of it.
How safe do you think my parser method is? Are there any mistakes in this code or can I use it safely?
Do you know any better, elegant or simpler solution for the cast?
First, your Parse method should put a constraint on T:
public static T Parse<T>(int value) where T : MyEnum
Second, you can make it protected instead and implement a casting operator in each of the derived enums this way:
public static explicit operator MyEnumChild1(int value)
{
return Parse<MyEnumChild1>(value);
}
And use it in a more classic way:
MyEnumChild1 mec1 = (MyEnumChild1)1
In Java, we can declare enums like so
public enum ChangeFlag
{
NEW("New"),
DELETED("Deleted"),
REVISED("Revised");
private final String text;
ChangeFlag(String text)
{
this.text = text;
}
public String toString()
{
return text;
}
}
Is there any elegant equivalent to this for C#?
Edit:
public static class FooExtensions
{
public static string GetDescription(this Foo #this)
{
switch (#this)
{
case Foo.Bar:
return "A bar";
}
}
}
Could you explain what the parameters in GetDescription(this Foo #this) mean?
I'm not used to seeing what this Foo #this refers to
You can use DescriptionAttribute:
public enum Foo
{
[Description("A bar")]
Bar
}
Which you would then extract via TypeDescriptor.GetAttributes or Type.GetCustomAttributes.
Or you could use extension methods:
public enum Foo
{
Bar
}
public static class FooExtensions
{
public static string GetDescription(this Foo #this)
{
switch (#this)
{
case Foo.Bar:
return "A bar";
}
}
}
// consuming code
var foo = Foo.Bar;
var description = foo.GetDescription();
The latter approach also gives you more control when it comes to localization, since you could always look up the description in a resource file, for example.
internal static class Program
{
private static void Main(string[] args)
{
ChangeFlag changeFlag = ChangeFlag.REVISED;
Console.WriteLine(changeFlag.GetDescription());
Console.Read();
}
public enum ChangeFlag
{
[Description("New")]
NEW,
[Description("Deleted")]
DELETED,
[Description("Revised")]
REVISED
}
}
public static class EnumExtensions
{
public static string GetDescription(this Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
if (fi != null)
{
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
return (attributes.Length > 0) ? attributes[0].Description : value.ToString();
}
return value.ToString();
}
}
A compact and fault-proof implementation variant, of the enum description getter extension method:
/// <exception cref="AmbiguousMatchException">More attributes found. </exception>
/// <exception cref="TypeLoadException">Cannot load custom attribute.</exception>
public static string GetDescription(this Enum value)
{
Type type = value.GetType();
string enumName = Enum.GetName(type, value);
if (enumName == null)
{
return null; // or return string.Empty;
}
FieldInfo typeField = type.GetField(enumName);
if (typeField == null)
{
return null; // or return string.Empty;
}
var attribute = Attribute.GetCustomAttribute(typeField, typeof(DescriptionAttribute));
return (attribute as DescriptionAttribute)?.Description; // ?? string.Empty maybe added
}
Also a comparison extension method (which uses the upper) for the description may be useful:
public static bool DescriptionEquals(this Enum value, string inputForComparison,
StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
{
string description;
try
{
description = value.GetDescription();
}
catch (Exception ex) when (ex is AmbiguousMatchException || ex is TypeLoadException)
{
return false;
}
if (description == null || inputForComparison == null)
{
return false;
}
return inputForComparison.Equals(description, comparisonType);
// || inputForComparison.Equals(value.ToString(), comparisonType); may be added
}
I have seen lots of method to convert a string to an enum using generics but cannot find a neat way to convert an enum to string using generics.
What I mean is Pass an enum and a value and return the mapped name of the enum.
Any suggestions
How about:
enum E
{
A = 2,
B = 3
}
public static string GetLiteral<T>(object value)
{
return Enum.GetName(typeof(T), value);
}
static void Main(string[] args)
{
Console.WriteLine(GetLiteral<E>(2));
Console.WriteLine(GetLiteral<E>(3));
}
This works when you know the value, and type of the enum but you want to get the enum instance back that is matching value..
static T ConvertToEnum<T>(object value)
{
return (T) Enum.Parse(typeof(T), Enum.GetName(typeof(T), value));
}
static void Main(string[] args)
{
Gender g1 = ConvertToEnum<Gender>(0); //Male
Gender g2 = ConvertToEnum<Gender>(1); //Female
Gender g3 = ConvertToEnum<Gender>(2); //*BANG* exception
}
I would write a extension method to do so eg
using System.ComponentModel;
public enum StatusResult
{
[Description("Success")]
Success,
[Description("Failure...")]
Failure
}
public static class AttributesHelperExtension
{
public static string ToDescription(this Enum value)
{
DescriptionAttribute[] da = (DescriptionAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
return da.Length > 0 ? da[0].Description : value.ToString();
}
public static T ToEnum<T>(this string stringValue, T defaultValue)
{
foreach (T enumValue in Enum.GetValues(typeof(T)))
{
DescriptionAttribute[] da = (DescriptionAttribute[])(typeof(T).GetField(enumValue.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
if (da.Length > 0 && da[0].Description == stringValue)
return enumValue;
}
return defaultValue;
}
}
Now to call this use
string value = StatusResult.Failure.ToDescription();
I came across this method that I used to use a while ago.
It uses the Extensions, and should always return an enum
public static T ToEnum<T>(this string type, T defaultEnum)
{
T holder;
try
{
holder = (T)Enum.Parse(typeof(T), type);
}
catch
{
holder = defaultEnum;
}
return holder;
}