I am trying to get the description from an array of enums bascically this is the current structure that I have.
public enum IllinoisNonDisclosureConvictionFormOptions
{
[Description("625 ILCS 5/11-501 - Driving Under the Influence")]
answerConviction0 = 0,
[Description("625 ILCS 5/11-503 - Reckless Driving")]
answerConviction1 = 1,
[Description("a violation of Article 11 of the Criminal Code of 1961, not including prostitution under 720 ILCS 5 / 11 - 14")]
answerConviction2 = 2,
[Description("720 ILCS 5/26-5 - Dog Fighting")]
answerConviction3 = 3,
[Description("720 ILCS 5/12-1 - Assault")]
answerConviction4 = 4,
}
So basically a user will select the crime they committed and then that text will be compared in a if statement to the description of the enums. What I currently have is this:
if (request.Question4 != null)
{
var answersForQuestion4 = Enum.GetValues(typeof(IllinoisNonDisclosureConvictionFormOptions)).Cast<IllinoisNonDisclosureConvictionFormOptions>().ToList();
foreach (Enum answer in answersForQuestion4)
{
//I need to compare the description to the selected text
string description = (enum description value)
if (request.Question4 == description)
{return description}
}
}
I may have to switch from enums to ControllersConstants since I dont really need to save their answers in the database. Please let me know if you have any insights regarding this matter.
This posted question (Get Enum from Description attribute) includes getting the enum description.
If you need the opposite and know that the responses MUST match your enum description, you can work backwards to get the enum using Max's answer.
The solution you posted seems to be looking for a matching enum name (e.g. answerConviction0) instead of a matching description as described in the question.
You can do something like this:
string findMe = "625 ILCS 5/11-503 - Reckless Driving";
Type enumType = typeof(IllinoisNonDisclosureConvictionFormOptions);
Type descriptionAttributeType = typeof(DescriptionAttribute);
foreach (string memberName in Enum.GetNames(enumType))
{
MemberInfo member = enumType.GetMember(memberName).Single();
string memberDescription = ((DescriptionAttribute)Attribute.GetCustomAttribute(member, descriptionAttributeType)).Description;
if (findMe.Equals(memberDescription))
{
Console.WriteLine("Found it!");
}
}
Note that all this reflection will be slow. Maybe you would be better off with an array of strings instead of an enumeration with descriptions.
Thank you so much for the positive feedback after reading through the posts I realized that my mistake was that answer was being set to an ENUM instead of an INT. I believe that this code format will give me the desired result:
if (request.Question4 != null)
{
var answersForQuestion4 = Enum.GetValues(typeof(IllinoisNonDisclosureConvictionFormOptions)).Cast<IllinoisNonDisclosureConvictionFormOptions>().ToList();
foreach (int answer in answersForQuestion4)
{
string descrip = Enum.GetName(typeof(IllinoisNonDisclosureConvictionFormOptions), answer);
if(descrip == request.Question4)
{
documentModel.Sections.Add(new Section(documentModel, new Paragraph(documentModel, descrip)));
}
}
}
This post helped a lot!
Get Enum from Description attribute
Related
I'm working on small C# / .NET Core app (REST API) and user is able to post string through Postman which might have following values:
"Day Shift", "Night Shift", "Part Time"
And I also have enum values defined as:
public enum Shifts
{
[Display(Name = "Day Shift")]
DayShift = 1,
[Display(Name = "Night Shift")]
NightShift = 2,
[Display(Name = "Part Time Shift")]
PartTimeShift = 3
}
Since I'm receiving values as string, I wrote simple method to ensure that provided value exists in my enums:
private bool IsValidEnumValue(string shiftType)
{
var successfullyParsed = Enum.TryParse(shiftType, out Shifts shifts);
return successfullyParsed;
}
Then I realised that I must take care of a upper/lower letters so I modified method to look like this:
private bool IsValidEnumValue(string shiftType)
{
// CODE BELOW THROWS EXCEPTION
var shiftType = (Shifts)Enum.Parse(typeof(Shifts), shiftType, true);
}
So my question is actually if user passes in "night shift" to recognize if that value is part of my defined enum type.
[Display(Name = "Night Shift")]
NightShift = 2,
But this obviously ain't working and I'm stuck here.
Any kind of help would be awesome!
Thanks guys.
Cheers
How about this (removing the spaces and using the generic method case insensitive):
private bool IsValidEnumValue(string shiftType)
{
return Enum.TryParse<Shifts>(shiftType.Replace(" ", ""), true, out Shifts _);
}
You will have to use reflection and extension methods. It is one of the reasons why I don't really like using Data Annotation with Enums. There are better solutions out there, but here is what you need to do.
internal static Shifts ToEnum(this Shifts e, string enumDisplayValue)
{
Type type = e.GetType();
MemberInfo[] members = type.GetMembers(BindingFlags.Static | BindingFlags.Public); // Only return Enum constants
if (members.Length > 0)
{
for (int i = 0; i < members.Length; i++)
{
if (members[i].GetCustomAttribute<DisplayAttribute>().Name.Equals(enumDisplayValue))
return (Shifts)Enum.ToObject(typeof(Shifts), e);
}
}
return 0; // Invalid value
}
Hope that helps!
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);
I need to convert a List of enums values to a single string to store in my db; then convert back again when I retrieve from the database.
Each enum's value is currently a simple integer, so it feels a bit overkill to create an extra table to deal with this.
So, in the example below, if the user selects Mother, Father and Sister, then the value stored in the database will be "0,1,3"
public enum MyEnum
{
Mother = 0,
Father = 1,
Gran = 2,
Sister = 3,
Brother = 4
}
I'm new to c#, so not sure if there is a nice out-the-box way to do this - I couldn't find anything obvious when google hunting!
Cheers in advance :)
- L
Enum's are explicitely able to be cast to/from integers
int value = (int)MyEnum.Mother;
and
MyEnum value = (MyEnum)1;
For strings use ToString and Enum.Parse
string value = MyEnum.Mother.ToString();
and
MyEnum value = (MyEnum)Enum.Parse(typeof(MyEnum),"Mother");
If you change you enum values to:
[Flags]
public enum MyEnum
{
Mother = 1,
Father = 2,
Gran = 4,
Sister = 8,
Brother = 16,
}
Then you could store Father and Gran as 6
Sister and Brother as 24 etc
by using binary numbers you should not get duplicate values by combining them
The following will convert back and forth between an array of Enum values via "0,1,3" as requested:
MyEnum[] selection = { MyEnum.Mother, MyEnum.Father, MyEnum.Sister };
string str = string.Join(",", selection.Cast<int>());
MyEnum[] enm = str.Split(',').Select(s => int.Parse(s)).Cast<MyEnum>().ToArray();
from your code it is
MyEnum a = MyEnum.Mother;
string thestring = a.ToString();
MyEnum b = (MyEnum) Enum.Parse(typeof(MyEnum), thestring);
Just use ToString to convert to the name, and the use Enum.TryParse (or Enum.Parse if you're not on .NET 4) to convert back.
If you're wanting one enum field to contain multiple values (e.g MyEnum.Mother | MyEnum.Father), you'll need to convert that to a Flags enum, as #WraithNath suggested. Otherwise you're talking about storing each option separately (there's no way to store Mother and Father in the same field with your current setup).
String Equivelant
MyEnum value = MyEnum.Father;
value.ToString(); // prints Father
Parsing
(MyEnum)Enum.Parse(typeof(MyEnum), "Father"); // returns MyEnum.Father
Enums can be cast to and from integer values. That's probably your best bet.
If you really want to use strings, ToString will return "Mother" "Father" "Gran" etc. Casting back from a string would just be a function:
private MyEnum GetEnumValue(string fromDB)
{
if( fromDB == "Mother" ) return MyEnum.Mother;
else if( fromDB == "Father") return MyEnum.Father;
//etc. etc.
}
EDIT:
Ian's answer for casting back is the more "C#-ey" way of doing it, and is far more extensible (handles adding new values to the enum much more flexibly).
Further to Jamiec's suggestion (which fits well for your need), if you need to defensively code your casting, try:
if (Enum.IsDefined(typeof(MyEnum), <your database value>))
{
// Safe to convert your enumeration at this point:
MyEnum value = (MyEnum)1;
}
This question already has answers here:
Get enum from enum attribute
(7 answers)
Closed 9 years ago.
This may seem a little upside down faced, but what I want to be able to do is get an enum value from an enum by its Description attribute.
So, if I have an enum declared as follows:
enum Testing
{
[Description("David Gouge")]
Dave = 1,
[Description("Peter Gouge")]
Pete = 2,
[Description("Marie Gouge")]
Ree = 3
}
I'd like to be able to get 2 back by supplying the string "Peter Gouge".
As a starting point, I can iterate through the enum fields and grab the field with the correct attribute:
string descriptionToMatch = "Peter Gouge";
FieldInfo[] fields = typeof(Testing).GetFields();
foreach (FieldInfo field in fields)
{
if (field.GetCustomAttributes(typeof(DescriptionAttribute), false).Count() > 0)
{
if (((DescriptionAttribute)field.GetCustomAttributes(typeof(DescriptionAttribute), false)[0]).Description == descriptionToMatch)
{
}
}
}
But then I'm stuck as to what to do in that inner if. Also not sure if this is the way to go in the first place.
Using the extension method described here :
Testing t = Enum.GetValues(typeof(Testing))
.Cast<Testing>()
.FirstOrDefault(v => v.GetDescription() == descriptionToMatch);
If no matching value is found, it will return (Testing)0 (you might want to define a None member in your enum for this value)
return field.GetRawConstantValue();
You could of course cast it back to Testing if required.
Ok, after typing all that I think this is a case of a decision right at the beginning leading me down the wrong path. Enum seemed the right way to go to start with, but a simple Dictionary<string, int> will suffice and be a hell of a lot easier to work with!
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
}