Does anyone know how to transform a enum value to a human readable value?
For example:
ThisIsValueA should be "This is Value A".
Converting this from a vb code snippet that a certain Ian Horwill left at a blog post long ago... i've since used this in production successfully.
/// <summary>
/// Add spaces to separate the capitalized words in the string,
/// i.e. insert a space before each uppercase letter that is
/// either preceded by a lowercase letter or followed by a
/// lowercase letter (but not for the first char in string).
/// This keeps groups of uppercase letters - e.g. acronyms - together.
/// </summary>
/// <param name="pascalCaseString">A string in PascalCase</param>
/// <returns></returns>
public static string Wordify(string pascalCaseString)
{
Regex r = new Regex("(?<=[a-z])(?<x>[A-Z])|(?<=.)(?<x>[A-Z])(?=[a-z])");
return r.Replace(pascalCaseString, " ${x}");
}
(requires, 'using System.Text.RegularExpressions;')
Thus:
Console.WriteLine(Wordify(ThisIsValueA.ToString()));
Would return,
"This Is Value A".
It's much simpler, and less redundant than providing Description attributes.
Attributes are useful here only if you need to provide a layer of indirection (which the question didn't ask for).
The .ToString on Enums is relatively slow in C#, comparable with GetType().Name (it might even use that under the covers).
If your solution needs to be very quick or highly efficient you may be best of caching your conversions in a static dictionary, and looking them up from there.
A small adaptation of #Leon's code to take advantage of C#3. This does make sense as an extension of enums - you could limit this to the specific type if you didn't want to clutter up all of them.
public static string Wordify(this Enum input)
{
Regex r = new Regex("(?<=[a-z])(?<x>[A-Z])|(?<=.)(?<x>[A-Z])(?=[a-z])");
return r.Replace( input.ToString() , " ${x}");
}
//then your calling syntax is down to:
MyEnum.ThisIsA.Wordify();
Most examples of this that I've seen involve marking your enum values up with [Description] attributes and using reflection to do the "conversion" between the value and the description. Here's an old blog post about it:
<Link>
You can inherit from the "Attribute" class of System.Reflection to create your own "Description" class. Like this (from here):
using System;
using System.Reflection;
namespace FunWithEnum
{
enum Coolness : byte
{
[Description("Not so cool")]
NotSoCool = 5,
Cool, // since description same as ToString no attr are used
[Description("Very cool")]
VeryCool = NotSoCool + 7,
[Description("Super cool")]
SuperCool
}
class Description : Attribute
{
public string Text;
public Description(string text)
{
Text = text;
}
}
class Program
{
static string GetDescription(Enum en)
{
Type type = en.GetType();
MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(Description), false);
if (attrs != null && attrs.Length > 0)
return ((Description)attrs[0]).Text;
}
return en.ToString();
}
static void Main(string[] args)
{
Coolness coolType1 = Coolness.Cool;
Coolness coolType2 = Coolness.NotSoCool;
Console.WriteLine(GetDescription(coolType1));
Console.WriteLine(GetDescription(coolType2));
}
}
}
You can also take a look at this article: http://www.codeproject.com/KB/cs/enumdatabinding.aspx
It's specifically about data binding, but shows how to use an attribute to decorate the enum values and provides a "GetDescription" method to retrieve the text of the attribute. The problem with using the built-in description attribute is that there are other uses/users of that attribute so there is a possibility that the description appears where you don't want it to. The custom attribute solves that issue.
I found it best to define your enum values with an under score so ThisIsValueA would be This_Is_Value_A then you can just do a enumValue.toString().Replace("_"," ") where enumValue is your varible.
An alternative to adding Description attributes to each enumeration is to create an extension method. To re-use Adam's "Coolness" enum:
public enum Coolness
{
NotSoCool,
Cool,
VeryCool,
SuperCool
}
public static class CoolnessExtensions
{
public static string ToString(this Coolness coolness)
{
switch (coolness)
{
case Coolness.NotSoCool:
return "Not so cool";
case Coolness.Cool:
return "Cool";
case Coolness.VeryCool:
return "Very cool";
case Coolness.SuperCool:
return Properties.Settings.Default["SuperCoolDescription"].ToString();
default:
throw new ArgumentException("Unknown amount of coolness", nameof(coolness));
}
}
}
Although this means that the descriptions are further away from the actual values, it allows you to use localisation to print different strings for each language, such as in my VeryCool example.
Enum.GetName(typeof(EnumFoo), EnumFoo.BarValue)
Related
This question already has answers here:
Enum from string, int, etc
(7 answers)
Closed 8 years ago.
I am working on WCF service and want to return preference key as enum rather than string.
How to make enum of preferencekey column which is string type in best optimized way?
You should use the enum.Parse Method:
MyEnum myEnum = (MyEnum)Enum.Parse(typeof(MyEnum), enumString);
I found the code snippet.
Rohit,
The value of preferenceKey could not easily be converted to an enum as you would expect. The strings could be parsed using Enum.Parse() method however the enum names must be different than what you have in the database. The problems are
Your string starts with a number
Your string contains the - characters
Now that being said you could design a different approach to your naming convetion of an enum as an example (I dont like this example personally but might work).
First define a new attribute called EnumName this attribute will be used to decorate your enums with the name that you expect from the database. Such as
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
public sealed class EnumNameAttribute : Attribute
{
readonly string name;
public EnumNameAttribute(string name)
{
this.name = name;
}
public string Name { get { return this.name; } }
}
The next step will be to define your enums (what I dont like is the names)
public enum Preferences
{
[EnumName("6E-SF-TYPE")]
SIX_E_SF_TYPE = 0,
[EnumName("6E-SF-VALUE")]
SIX_E_SF_VALUE = 1
}
Simple enough, we have our enum with each item decorated with the EnumName attribute. The next step will be to create a method to parse the enum based on the string from the database.
public static class EnumNameParser
{
public static Preferences ParseString(string enumString)
{
var members = typeof(Preferences).GetMembers()
.Where(x => x.GetCustomAttributes(typeof(EnumNameAttribute), false).Length > 0)
.Select(x =>
new
{
Member = x,
Attribute = x.GetCustomAttributes(typeof(EnumNameAttribute), false)[0] as EnumNameAttribute
});
foreach(var item in members)
{
if (item.Attribute.Name.Equals(enumString))
return (Preferences)Enum.Parse(typeof(Preferences), item.Member.Name);
}
throw new Exception("Enum member " + enumString + " was not found.");
}
}
This method simply takes an input stream, evaluates all the EnumNameAttributes and returns the first match (or exception if not found).
Then this can be called such as.
string enumString = "6E-SF-TYPE";
var e = EnumNameParser.ParseString(enumString);
Now if you want to take the enum and get the name for the database you can extend your helper method with
public static string GetEnumName(this Preferences preferences)
{
var memInfo = typeof(Preferences).GetMember(preferences.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(EnumNameAttribute), false);
if (attrs != null && attrs.Length > 0)
return ((EnumNameAttribute)attrs[0]).Name;
}
throw new Exception("No enum name attribute defined");
}
I really would recommend storing the numerical values rather than the text values in the database. If you want the text values in the database too then add a table for it. Regardless, the Enum.Parse and .TryParse methods will convert a String and the .ToObject method will convert either text or numbers.
How to make enum of preferencekey column which is string type in best optimized way
Well i am afraid you cannot use your preference key as enum for 2 reasons.
your preference key is starting with integer values making it an in-valid identifier.
it also contains - which is not allowed either.
However, if you are able to convert your preference key to some valid identifiers then you can do this.
i would recomment using Enum.TryParse for parsing because
TryParse(String, Boolean, TEnum) is identical to the Parse(Type, String, Boolean) method, except that instead of throwing an exception, it returns false if the conversion fails. It eliminates the need for exception handling when parsing the string representation of an enumeration value.
Something like this
string testingString = "Test1";
SomeEnum result;
if (Enum.TryParse(testingString, out result))
{
Console.WriteLine("Success");
}
or if case sensitivity doesn't matter to you. Then you can use the overload like this
if (Enum.TryParse(testingString,true, out result))
Console.WriteLine("Success");
where SomeEnum is
public enum SomeEnum
{
Test1 = 1,
Test2 = 2
}
The simples way to do this would be:
1) create an enum representing all possible preference key values, but add a 'invalid' with value -1.
enum PreferenceKey
{
INVALID = -1,
SIX_E_SF_TYPE = 0,
SIX_E_SF_VALUE = 1,
...
}
2) create a list of strings containing the string representations of all preference key values in the same order as the enum.
private List<string> strings = new List<string> {"6E-SF-TYPE", "6E-SF-VALUE", ...};
3) Lookup the column value in the list of strings and cast the position to the enum.
If the column value cannot be found in the list of strings, IndexOf will return -1, which is the 'invalid' value.
PreferenceKey key = (PreferenceKey) strings.IndexOf(preferenceKeyColumnValue);
How can I effective extend enum to have more than 2 options.
I am reading events from a file, line-by-line.
I have a constructor
public enum EventType
{ A,D }
public class Event
{
public EventType Type { get; set; }
}
I assigned Type property like this:
Type = tokens[2].Equals("A") ? EventType.A : EventType.D,
where token[2] is the string that holds values like "A".
This works fine when there are only A and D, but I want to have 2 more types; say R and C. When I add them to enum field, how can I get the type? The above is giving compilation errors as if using Type as a variable.
I appreciate your immediate help!
Thanks
There are really only three sensible ways to go about this:
Enum.TryParse
If the tokens will always correspond exactly to your enum members, you can use Enum.TryParse:
EventType type;
if (Enum.TryParse(tokens[2], out type)) {
Type = type;
}
else { /* token does not exist as an enum member */ }
This approach is the simplest, but it's probably slower than the next one and it also has another drawback: the author of the code that provides tokens[2] and the author of the enum must always keep their code in sync.
Use a dictionary
var dict = new Dictionary<string, EventType>
{
{ "A", EventType.A },
{ "D", EventType.D },
// more items here
}
Type = dict[tokens[2]]; // no error checking, please add some
This requires some setup, but it's probably the fastest and it also allows accounting for changes in the input strings and/or enum values.
Use an attribute
Alternatively, you can annotate your enum members with a custom attribute and write a helper method that uses reflection to find the correct member based on the value of this attribute. This solution has its uses but it's the least likely candidate; most of the time you should prefer one of the two alternatives.
You can want to use Enum.Parse to get the matching value:
Type = Enum.Parse(typeof(EventType), tokens[2])
If tokens[2] is not defined in EventType, Enum.Parse throws an exception, so you can use Enum.IsDefined to check if there is an enum value for the string:
Enum.IsDefined(typeof(EventType), tokens[2])
You may use Enum.Parse to parse a string. For error handling you may use Enum.GetNames(typeof(EventType)) and iterate over the returned string array, which contains all possible names of the enum.
var type = (EventType)Enum.Parse(typeof(EventType), tokens[2]);
EventType et;
switch(tokens[2])
{
case "A":
et=EventType.A;
break;
case "B":
et=EventType.B;
break;
case "C":
et=EventType.C;
break;
}
return et;
Why is this even possible? Is it a bug?
using System;
public class InvalidEnumParse
{
public enum Number
{
One,
Two,
Three,
Four
}
public static void Main()
{
string input = "761";
Number number = (Number)Enum.Parse(typeof(Number), input);
Console.WriteLine(number); //outputs 761
}
}
That's just the way enums work in .NET. The enum isn't a restrictive set of values, it's really just a set of names for numbers (and a type to collect those names together) - and I agree that's a pain sometimes.
If you want to test whether a value is really defined in the enum, you can use Enum.IsDefined after parsing it. If you want to do this in a more type-safe manner, you might want to look at my Unconstrained Melody project which contains a bunch of constrained generic methods.
If you have a enum with [Flags] attribute, you can have any value combination. For instance:
[Flags]
enum Test
{
A = 1,
B = 2,
C = 4,
D = 8
}
You could to do this:
Test sample = (Test)7;
foreach (Test test in Enum.GetValues(typeof(Test)))
{
Console.WriteLine("Sample does{0} contains {1}",
(sample & test) == test ? "": " not", test);
}
I'm working on this homework project and having trouble understanding the text explaining how to correctly take the accessed value of the enumeration and then apply the string array value to it. Can you please help me understand this? The text we are using is very difficult and poorly written for a beginner to understand, so I'm kind of on my own here. I've got the first parts written, but need some help on the accessing of the enumeration value and assigning, I think I'm close, but don't understand how to properly get and set the values on this.
Write a class, MyCourses, that contains an enumeration of all the courses that you are currently taking. This enum should be nested inside of your class MyCourses. Your class should also have an array field that provides a short description (as a String) of each of your courses. Write an indexer that takes one of your enumerated courses as an index and returns the String description of the course.
namespace Unit_4_Project
{
public class MyCourses
{
// enumeration that contains an enumeration of all the courses that
// student is currently enrolled in
public enum CourseName
{
IT274_01AU,
CS210_06AU
}
// array field that provides short description for each of classes,
// returns string description of the course
private String[] courseDescription =
{"Intermediate C#: Teaches intermediate elements of C# programming and software design",
"Career Development Strategies: Teaches principles for career progression, resume preparation, and overall self anaylsis"};
// indexer that takes one of the enumerated courses as an index
// and returns the String description of the course
public String this[CourseName index]
{
get
{
if (index == 1)
return courseDescription[0];
else
return courseDescription[1];
}
set
{
if (index == 1)
courseDescription[0] = value;
else
courseDescription[1] = value;
}
}
}
}//end public class MyCourses
You're close, you just went a little nutty there at the end. The CourseName is nothing but a number. You can index directly into your courseDescription array ...
courseDescription[(int)index]
and you have it. :)
What you're missing is that enums convert to ints. (In fact, under they covers, they basically are ints.)
And arrays can be indexed by ints.
Try indexing your array with a parameter of with the type of your enum.
Here is my response from CodeGuru:
Enumerations are strongly typed, so you cannot compare it to an int directly. You can however cast the enumeration to an int. So you would have this instead:
if ( ( ( int ) index ) == 1)
return courseDescription[0];
else
return courseDescription[1];
Enums do not implicitly convert to ints. But you can explicitly convert them.
public String this[CourseName index]
{
get { return courseDescription[(int)index]; }
set { courseDescription[(int)index] = value; }
If you are going to use enums this way, you should define the actual numerical value they represent.
public enum CourseName
{
IT274_01AU = 0,
CS210_06AU = 1
}
While the current implementation of enums will work, there is nothing that says it will do so in the future.
The trick here is that Enumerations are integral datatypes at their core. This means you can cast back and forth between Enum and Int32 if you want to do so:
You need to change the "get" section to:
public String this[CourseName index]
{
get {
return courseDescription[(int)index];
}
}
This works since the enum is basically equivalent to:
public enum CourseName
{
IT274_01AU = 0,
CS210_06AU = 1
}
I know this rather goes against the idea of enums, but is it possible to extend enums in C#/Java? I mean "extend" in both the sense of adding new values to an enum, but also in the OO sense of inheriting from an existing enum.
I assume it's not possible in Java, as it only got them fairly recently (Java 5?). C# seems more forgiving of people that want to do crazy things, though, so I thought it might be possible some way. Presumably it could be hacked up via reflection (not that you'd every actually use that method)?
I'm not necessarily interested in implementing any given method, it just provoked my curiosity when it occurred to me :-)
The reason you can't extend Enums is because it would lead to problems with polymorphism.
Say you have an enum MyEnum with values A, B, and C , and extend it with value D as MyExtEnum.
Suppose a method expects a myEnum value somewhere, for instance as a parameter. It should be legal to supply a MyExtEnum value, because it's a subtype, but now what are you going to do when it turns out the value is D?
To eliminate this problem, extending enums is illegal
You're going the wrong way: a subclass of an enum would have fewer entries.
In pseudocode, think:
enum Animal { Mosquito, Dog, Cat };
enum Mammal : Animal { Dog, Cat }; // (not valid C#)
Any method that can accept an Animal should be able to accept a Mammal, but not the other way around. Subclassing is for making something more specific, not more general. That's why "object" is the root of the class hierarchy. Likewise, if enums were inheritable, then a hypothetical root of the enum hierarchy would have every possible symbol.
But no, C#/Java don't allow sub-enums, AFAICT, though it would be really useful at times. It's probably because they chose to implement Enums as ints (like C) instead of interned symbols (like Lisp). (Above, what does (Animal)1 represent, and what does (Mammal)1 represent, and are they the same value?)
You could write your own enum-like class (with a different name) that provided this, though. With C# attributes it might even look kind of nice.
When built-in enums aren't enough, you can do it the old fashion way and craft your own. For example, if you wanted to add an additional property, for example, a description field, you could do it as follows:
public class Action {
public string Name {get; private set;}
public string Description {get; private set;}
private Action(string name, string description) {
Name = name;
Description = description;
}
public static Action DoIt = new Action("Do it", "This does things");
public static Action StopIt = new Action("Stop It", "This stops things");
}
You can then treat it like an enum like so:
public void ProcessAction(Action a) {
Console.WriteLine("Performing action: " + a.Name)
if (a == Action.DoIt) {
// ... and so on
}
}
The trick is to make sure that the constructor is private (or protected if you want to inherit), and that your instances are static.
Enums are supposed to represent the enumeration of all possible values, so extending rather does go against the idea.
However, what you can do in Java (and presumably C++0x) is have an interface instead of a enum class. Then put you standard values in an enum that implements the feature. Obviously you don't get to use java.util.EnumSet and the like. This is the approach taken in "more NIO features", which should be in JDK7.
public interface Result {
String name();
String toString();
}
public enum StandardResults implements Result {
TRUE, FALSE
}
public enum WTFResults implements Result {
FILE_NOT_FOUND
}
You can use .NET reflection to retrieve the labels and values from an existing enum at run-time (Enum.GetNames() and Enum.GetValues() are the two specific methods you would use) and then use code injection to create a new one with those elements plus some new ones. This seems somewhat analagous to "inheriting from an existing enum".
I didn't see anyone else mention this but the ordinal value of an enum is important. For example, with grails when you save an enum to the database it uses the ordinal value. If you could somehow extend an enum, what would be the ordinal values of your extensions? If you extended it in multiple places how could you preserve some kind of order to these ordinals? Chaos/instability in the ordinal values would be a bad thing which is probably another reason why the language designers have not touched this.
Another difficulty if you were the language designer, how can you preserve the functionality of the values() method which is supposed to return all of the enum values. What would you invoke this on and how would it gather up all of the values?
Adding enums is a fairly common thing to do if you go back to the source code and edit, any other way (inheritance or reflection, if either is possible) is likely to come back and hit you when you get an upgrade of the library and they have introduced the same enum name or the same enum value - I have seen plenty of lowlevel code where the integer number matches to the binary encoding, where you would run into problems
Ideally code referencing enums should be written as equals only (or switches), and try to be future proof by not expecting the enum set to be const
If you mean extends in the Base class sense, then in Java... no.
But you can extend an enum value to have properties and methods if that's what you mean.
For example, the following uses a Bracket enum:
class Person {
enum Bracket {
Low(0, 12000),
Middle(12000, 60000),
Upper(60000, 100000);
private final int low;
private final int high;
Brackets(int low, int high) {
this.low = low;
this.high = high;
}
public int getLow() {
return low;
}
public int getHigh() {
return high;
}
public boolean isWithin(int value) {
return value >= low && value <= high;
}
public String toString() {
return "Bracket " + low + " to " + high;
}
}
private Bracket bracket;
private String name;
public Person(String name, Bracket bracket) {
this.bracket = bracket;
this.name = name;
}
public String toString() {
return name + " in " + bracket;
}
}
Saw a post regarding this for Java a while back, check out http://www.javaspecialists.eu/archive/Issue161.html .
I would like to be able to add values to C# enumerations which are combinations of existing values. For example (this is what I want to do):
AnchorStyles is defined as
public enum AnchorStyles {
None = 0,
Top = 1,
Bottom = 2,
Left = 4,
Right = 8,
}
and I would like to add an AnchorStyles.BottomRight = Right + Bottom so instead of saying
my_ctrl.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;
I can just say
my_ctrl.Anchor = AnchorStyles.BottomRight;
This doesn't cause any of the problems that have been mentioned above, so it would be nice if it was possible.
A temporary/local workaround, when you just want very local/one time usage:
enum Animals { Dog, Cat }
enum AnimalsExt { Dog = Animals.Dog, Cat= Animals.Cat, MyOther}
// BUT CAST THEM when using:
var xyz = AnimalsExt.Cat;
MethodThatNeedsAnimal( (Animals)xyz );
See all answers at: Enum "Inheritance"
You can't inherit from/extend an enum, you can use attributes to declare a description. If you're looking for an integer value, that's built-in.
Hmmm - as far as I know, this can't be done - enumerations are written at design-time and are used as a convenience to the programmer.
I'm pretty sure that when the code is compiled, the equivalent values will be substituted for the names in your enumeration, thereby removing the concept of an enumeration and (therefore) the ability to extend it.
Some time back even i wanted to do something like this and found that enum extensions would voilate lot of basic concepts... (Not just polymorphisim)
But still u might need to do if the enum is declared in external library and
Remember you should make a special caution when using this enum extensions...
public enum MyEnum { A = 1, B = 2, C = 4 }
public const MyEnum D = (MyEnum)(8);
public const MyEnum E = (MyEnum)(16);
func1{
MyEnum EnumValue = D;
switch (EnumValue){
case D: break;
case E: break;
case MyEnum.A: break;
case MyEnum.B: break;
}
}
As far as java is concerned it is not allowed because adding elements to an enum would effectively create a super class rather than a sub class.
Consider:
enum Person (JOHN SAM}
enum Student extends Person {HARVEY ROSS}
A general use case of Polymorphism would be
Person person = Student.ROSS; //not legal
which is clearly wrong.