Bear with me as this is a difficult concept for me. I have a method that returns the items in an enum as strings (for DB storage). Here is the method:
public static IEnumerable<SelectListItem> GetItemsFromEnum<T>
(T selectedValue = default(T)) where T : struct
{
return from name in Enum.GetNames(typeof(T))
let enumValue = Convert.ToString((T)Enum.
Parse(typeof(T), name, true))
select new SelectListItem
{
Text = GetEnumDescription(name, typeof(T)),
Value = enumValue,
Selected = enumValue.Equals(selectedValue)
};
}
(NB: GetEnumDescription is another method in the class that gets the [Display(Name="") text to display something friendly in the UI.)
For a single select input (radio button, drop down), this works great. However, with multi-selects (list box, check box list), I am thinking of using the enum [Flags] attribute to store in the DB as an int.
However, the GetItemsFromEnum method will not work in the case that I use [Flags] and requires that I change it so that the value assigned in the GetItemsFromEnum method isn't the string value of the enum, it's the int value.
This is actually a two-parter:
How can I modify the method so that enumValue would be the
value of the int from enum [Flags] (i.e., if "1 + 2" were selected
(two check boxes), then the int value saved would be "3")?
Most importantly, what kind of logic can I insert in the method
so that all my other enum's (those without [Flags]) are not
affected (i.e., it still converts ToString)? I was thinking some if ... else logic, but would that work?
First of all, the [Flags] attribute doesn't add special properties to the enum's values, it's just used through Reflection by the Enum class when formatting it as a string and to let people who use your code know that they can use bitwise operations on the enum safely, or in other words, without undesired results.
Let's take this enum:
[Flags]
enum MyEnum
{
Undefined,
Employee,
Student
}
And let's create a variable this way:
var employeeAndStudent = MyEnum.Employee | MyEnum.Student;
The variable, if cast to integer, is equals to 3. While the ToString() method will print "Employee, Student", Enum.GetNames doesn't have a value assigned for the field 3 -- Quite obviously, since it has no name. I can think of two solutions:
You create your own GetNames which will return, in addition to the defined names, also all the possible combinations of the enum's values, conveniently printed in your format.
You define the flags in the enum, which can become pretty wasteful if there are many members. In our case, MyEnum would become:
[Flags]
enum MyEnum
{
Undefined,
Employee,
Student,
EmployeeAndStudent
}
One more thing, your method seems to have a bug. This line:
Selected = enumValue.Equals(selectedValue)
Is trying to compare an enum type to a string, and will always result in false. Are you sure that SelectListItem.Value should be of type string? I suggest you to review your code.
To give direct answers to your question:
Add [Flags] to your enum and use the OR operator to combine values.
In your GetEnumDescription method, check if the type has the Flags attribute.
Related
Hey guys im not sure if what i want to do is right or not,
i have diffrent status in our network,which i have created a ENUM class for it:
public enum AllMachinesStatus
{
STOP,
START,
LINKDOWN,
ERROR,
LINK_UP,
IDLE,
}
in database i there is a service which binds these fields,they are all int,the show the number of the machine in each status which should vary from time to time,,now i want to get this data with linq and bind my class,do you think its a right way?or i should create a normal class with a constructor which whenever i call the class i can have the data?
var rslt=(from s in db.Machines
select new AllMachinesStatus{
//here i dont have access to the properties of enum class to bind them with Count()
}
If s in an integer with a valid value for AllMachinesStatus, try:
from s in db.Machines select (AllMachinesStatus)s
Basically, it is casting the int to AllMachinesStatus enum
Your issue is improper usage of enum here.
enum does not have a constructor, it is a strong type that has an implicit value type, but it is mostly suitable for signaling and flagging.
In this method, you would evaluate on s and either cast the correlating int value of s or a field\property of s to AllMachinesStatus or do Enum.Parse using s or a field\property of s (i.e. s.Status).
note that AllMachinesStatus enum has implicit int values.
public enum AllMachinesStatus
{
STOP, // 0
START, // 1
LINKDOWN, // 2
ERROR, // 3
LINK_UP, // 4
IDLE, // 5
}
Example of Enum.Parse with s.Status
// note that 'false' is being passed for case insensitive behavior in the method
var rslt=(from s in db.Machines
select (AllMachinesStatus)Enum.Parse(typeof(AllMachinesStatus), s.Status, false));
Alternatively,
if s had a field (I'll call BitFlag for purpose of example) correlating to the int value, you could us the following:
Example of casting int to AllMachinesStatus
var rslt=(from s in db.Machines
select (AllMachinesStatus)s.BitFlag);
Doc References:
MSDN System.Enum
MSDN Enum.Parse
EDIT1:
Include examples and corrected sentiment of using Enum.GetName to Enum.Parse
EDIT2:
update s to use question comment referenced s.Status existence.
I have an array of string values that I would like to have set flags on a Flags Enum object. I have several of these and was looking for a more generic way to pass in the type of the Flags enum and not have to duplicate the method for each Flags Enum type. This is what I have currently:
public static MyFlagsEnum ParseFlagsEnum(string[] values)
{
MyFlagsEnum flags = new MyFlagsEnum();
foreach (var flag in values)
{
flags |= (MyFlagsEnum)Enum.Parse(typeof(MyFlagsEnum), flag);
}
return flags;
}
I was looking for a more generic way of doing the same thing, while being able to use any Flags Enum type.
Enum.Parse can already combine multiple flags. Quoting from the documentation:
Remarks
The value parameter contains the string representation of an enumeration member's underlying value or named constant, or a list of named constants delimited by commas (,). One or more blank spaces can precede or follow each value, name, or comma in value. If value is a list, the return value is the value of the specified names combined with a bitwise OR operation.
So you could do it like this:
public static T ParseFlagsEnum<T>(string[] values)
{
return (T)Enum.Parse(typeof(T), string.Join(",", values));
}
I'm going to grab the enum value from a querystring.
For instance lets say I have this enum:
Enum MyEnum
{
Test1,
Test2,
Test3
}
I'm going to grab the value from an incoming querystring, so:
string myEnumStringValue = Request["somevar"];
myEnumStringValue could be "0", "1", "2"
I need to get back the actual Enum Constant based on that string value.
I could go and create a method that takes in the string and then perform a case statement
case "0":
return MyEnum.Test1;
break;
but there's got to be an easier or more slick way to do this?
Take a look at Enum.Parse, which can convert names or values to the correct enum value.
Once you have that, cast the result to MyEnum and call ToString() to get the name of the constant.
return ((MyEnum)Enum.Parse(typeof(MyEnum), Request["somevar"])).ToString();
There is built-in functionality for this task:
MyEnum convertedEnum = (MyEnum) Enum.Parse(typeof(MyEnum), myEnumStringValue);
You need to parse the string to get its integer value, cast the value to the Enum type, then get the enum value's name, like this:
string myEnumStringValue = ((MyEnum)int.Parse(Request["somevar"])).ToString();
EDIT: Or, you can simply call Enum.Parse. However, this should be a little bit faster.
i have to create an enum that contains values that are having spaces
public enum MyEnum
{
My cart,
Selected items,
Bill
}
This is giving error. Using concatenated words like MyCart or using underscore My_Cart is not an option. Please guide.
Thanks in advance.
From
enum (C# Reference)
An enumerator may not contain white
space in its name.
Enum just cant have space!
What do you need it for? If you need it simply for display purpose, you can stick with underscore and write an extension method for your enum so that you can ask for the display text by doing this (assuming your ext method is call DisplayText). Internally you just implement the DisplayText method to substitute "_" with space
MyEnum.My_Cart.DisplayText(); // which return "My Cart"
As per the C# specification, "An enumerator may not contain white space in its name."
(see http://msdn.microsoft.com/en-us/library/sbbt4032.aspx)
Why do you need this?
**
enums can't have spaces in C#!" you say. Here is the way
System.ComponentModel.DescriptionAttribute to add a more friendly
description to the enum values. The example enum can be rewritten like
**
public enum DispatchTypes
{
Inspection = 1,
LocalSale = 2,[Description("Local Sale")]
ReProcessing=3,[Description("Re-Processing")]
Shipment=4,
Transfer=5
}
Hence it returns "LocalSale" or "ReProcessing", when we use .ToString()
I agree the use of DisplayText if you are following convention. But if you need different display value to represent the enum constant, then you could have a constructor passing that value.
public enum MyEnum
{
My cart ("Cart"),
Selected items("All Selected Items"),
Bill("Payment");
private String displayValue;
private MyEnum(String displayValue) {
this.displayValue = displayValue;
}
public String displayText() {
return this.displayValue;
}
}
You can have a displayText method or a toString method which would return the displayValue
EDITED: Updated 3/23/09. See rest of post at bottom. I'm still having trouble with the indexer. Anymore help or examples would really help me out.
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.
Write a class MyFriends that contains an indexer that provides
access to the names of your friends.
namespace IT274_Unit4Project
{
public class MyCourses
{
// enumeration that contains an enumeration of all the courses that
// student is currently enrolled in
public enum CourseName {IT274= 0,CS210 = 1}
// 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
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.
Please do not provide me with direct code answers, unless a MSDN style explanation that is generalized and not specific to my project. ie:
public class MyClass
{ string field1;
string field2;
//properties
public string Value1
get etc...
Thanks!
First of all, the base type of an enumeration has to be a numeric value type, so you can't have an enumeration with base type string. The following isn't going to compile:
public enum CourseName
{
Class1 = "IT274-01AU: Intermediate C#",
Class2 = "CS210-06AU: Career Development Strategies"
}
So change it to use the default base type of int. Something like the following will do, but change the names as you see fit (you might want to use the course name instead of the code, for example). Remember also that you should use meaningful names whenever possible in an enumeration.
public enum Courses
{
IT274_01AU,
CS210_06AU
}
(I know you said you didn't want specific code examples, but I think this one illustrates my point much more clearly than any explanation.)
Second, you're on the right track with the indexer, but you have to think of how to relate the enumeration to the array of string descriptions. Remember, an enumeration is nothing more than a finite set of glorified (named) numbers. With the above Courses enumeration, you have two values named IT274_01AU and CS210_06AU. So in the indexer, you have to map each of these values to the string description. There are multiple ways to do it, but the simplest one would be a switch statement, for example:
switch (myEnum)
{
case value1:
return string1;
case value2:
return string2;
}
Another option, however is to explicitly map the enum values to its base type, and use the base type to index into your array. For example, if you have the enum
public enum Enumerations
{
value1 = 0,
value2 = 1
}
then you can index directly into an array using myArray[(int)myEnum]. This may be of use and is the slightly-more-advanced-but-less-lines-of-code-and-arguably-easier-to-understand method.
(resisting the urge to write code)
First off, an enumeration is a named list of integers and (per MSDN) the approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.
Also, remember that courseDescription is an array of strings and the purpose of the indexer is to give you an index into that array (ie. [0] returns the first string, [1] returns the second, etc.).