Associating Strings with enums in C#

Associating Strings with enums in C#

January 17, 2008 14:50 by Luke

I have seen other great articles out lining the benefits of some pretty clever and useful helper classes for enums. Many of these methods almost exactly mirror methods I had written in my own EnumHelper class. (Isn't it crazy when you imagine how much code duplication there must be like this out there!)

One thing that I don't see emphasized much is trying to associated string values with enums. For example, what if you want to have a Drop Down list that you can choose from a list of values (which are backed by an enum)? Lets start with a test enum:

public enum States
{
California,
NewMexico,
NewYork,
SouthCarolina,
Tennessee,
Washington
}

So if you made a drop down list out of this enum, using the ToString() method, you would get a drop down that looks like this:

image

While most people will understand this, it should really be displayed like this:

image

"But enums can't have spaces in C#!" you say. Well, I like to use the System.ComponentModel.DescriptionAttribute to add a more friendly description to the enum values. The example enum can be rewritten like this:

public enum States
{
California,
[Description("New Mexico")]
NewMexico,
[Description("New York")]
NewYork,
[Description("South Carolina")]
SouthCarolina,
Tennessee,
Washington
}

Notice that I do not put descriptions on items where the ToString() version of that item displays just fine.

How Do We Get To the Description?

Good question! Well, using reflection of course! Here is what the code looks like:

public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());

DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);

if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return
value.ToString();
}

This method first looks for the presence of a DescriptionAttribute and if it doesn't find one, it just returns the ToString() of the value passed in. So

GetEnumDescription(States.NewMexico);

returns the string "New Mexico".

A Free Bonus: How to Enumerate Enums

Ok, so now we know how to get the string value of an enum. But as a free bonus, I also have a helper method that allows you to enumerate all the values of a given enum. This will allow you to easily create a drop down list based on an enum. Here is the code for that method:

public static IEnumerable<T> EnumToList<T>()
{
Type enumType = typeof(T);

// Can't use generic type constraints on value types,
// so have to do check like this
if (enumType.BaseType != typeof(Enum))
throw new ArgumentException("T must be of type System.Enum");

Array enumValArray = Enum.GetValues(enumType);
List<T> enumValList = new List<T>(enumValArray.Length);

foreach (int val in enumValArray)
{
enumValList.Add((T)Enum.Parse(enumType, val.ToString()));
}

return enumValList;
}
As you can see, the code for either of these methods isn't too complicated. But used in conjunction, they can be really useful. Here is an example of how we would create the drop down list pictured above based on our enum:
DropDownList stateDropDown = new DropDownList();
foreach (States state in EnumToList<States>())
{
stateDropDown.Items.Add(GetEnumDescription(state));
}

Pretty simple huh? I hope you find this as useful as I do.

One More Example

There is one more scenario that I often find myself needing to associate string values with enums - when dealing with legacy constant string based system. Lets say you have a library that has the following method:

public void ExecuteAction(int value, string actionType)
{
if (actionType == "DELETE")
Delete();
else if (actionType == "UPDATE")
Update();
}
(I tried to make this look as legacy as I could for a contrived example). What happens if somebody passes in "MyEvilAction" as a value for actionType? Well, whenever I see hard coded strings, that is a code smell that could possibly point to the use of enums instead. But sometimes you don't have control over legacy code and you have to deal with it. So you could make an enum which looks like this:
public enum ActionType
{
[Description("DELETE")]
Delete,
[Description("UPDATE")]
Update
}
(I know, I know, this is a very contrived example) Then you could call the ExecuteAction Method like this:
 ExecuteAction(5, GetEnumDescription(ActionType.Delete));

This at least makes the code more readable and may also make it more consistent and secure.




Object Cloning c#.net

public static object CloneObject(object obj)
        {
            using (System.IO.MemoryStream memStream = new MemoryStream())
            {
                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(null,
                     new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Clone));
                binaryFormatter.Serialize(memStream, obj);
                memStream.Seek(0, SeekOrigin.Begin);
                return binaryFormatter.Deserialize(memStream);
            }
        }

How to deliver multiple dlls and exe as a single file

Scenario: You are developing a dotnet appliation, For that you are adding some external dlls ex:Office.dll. Normally we need to build the application and provide the directory containing dlls and exe for the customer. How to deliver all the files as a single pack. Is it possible if so how?
Solution: Download the ilmerge.exe from the below link and install it in your machine.

http://www.microsoft.com/downloads/details.aspx?FamilyID=22914587-B4AD-4EAE-87CF-B14AE6A939B0&displaylang=en


After Building your application go to the command prompt and give the below syntax.
"path<ilmerge.exe>" /out:"($TargetDir)ExpectedApplicationname.exe" "($TargetPath)" *.dll.....

example for the arguments:
"c:\programfiles\ilmerge\ilmerge.exe" /out:"c:\myApp\SingleFile.EXE" "c:\myApp\bin\debug\myApp.exe" "c:\myApp\bin\debug\office.exe"

(OR)

You can also provide this command in the postbuild command so the singlefile will created directly when you build the application.

BackgroundWorker Control

The BackgroundWorker class allows you to run an operation on a separate, dedicated thread.
Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running( i.e it seems like white faded screen ). In such a case this background worker will helpful so the fading are avoided bcoz it was running under seperate dedicated thread.

Three events available in backgroundworker.
1.DoWork: In which we need write the business logic
2.Runworkercompleted: This event automatically fired when the bgworker completes its process
3.Progresschanged: from which we can get the percentage of completed process.
 
To start the bgworker use the method RunWorkerAsync()

Consider the code snippet below create a win form and select 2 button as named BgworkerButton,NormalButton add a background worker as backgroundWorker1 and test it.
        string str = string.Empty;
        public Form1()
        {
            InitializeComponent();
        }

        private void BgworkerButton_Click(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 1; i <= 10000; i++)
                str = str + " bg" + i.ToString();
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            MessageBox.Show("Completed");
        }

        private void NormalButton_Click(object sender, EventArgs e)
        {
            for (int i = 1; i <= 10000; i++)
                str = str + " " + i.ToString();
            MessageBox.Show("Completed");
        }

Compare Generic.List vs Array

Consider that you r in a situation to use some collection object. What type you will prefer Generic.list or Array

Advantage of generic is, it is easy to handle. use the add, remove and new extension methods in .net2008 but which is efficient.

                     (i) for( int i = 0; i < 5000000; i++ )
{
for( int j = 0; j < Array.Length; j++ )
{
Array[j] = j;
}
}


(ii)for( int i = 0; i < 5000000; i++ )
{
for( int j = 0; j < List.Count; j++ )
{
List[j] = j;
}
}


the time for the execution is The results where 2620 for the Array and 13200 for the List in terms of nanoseconds.
The reasons are
1. it has to do with the memory not necessarily being contiguous, and so the lookup is slightly more complex
2. List generic version is actually making function calls in the generated code this will understand if u saw the IL code for the above two cases but not in case of array.
3. The List<T> class uses an array internally, and will do effectively the same operation as Array.Resize(). The only real difference between the two is that List<T> always doubles the size of the storage, so that you need to resize fewer and fewer times as the data gets larger. Of course, you could always use that strategy when using Array.Resize() as well,

preserving Array elements using c#.net

Consider the two arrays:
        string[] str = new string[1];
            str[0] = "str";
            string[] str1 = new string[2];
            str1[0] = "str1";
            str1[1] = "str2";

To append an two arraycollections:
str = str.Concat(str1).ToArray(); //the  result was stored in the str array. this will work only in .net 2008

To add new element in the array:
        Array.Resize(ref str, newSize);
            str[newSize-1] = "newvalue";

Convert string to datatime format

1.

string str = "24/10/2008";
DateTime dt = DateTime.ParseExact(str, "dd/MM/yyyy",
                                 
Thread.CurrentThread.CurrentCulture);


2.

DateTime date = System.DateTime.ParseExact(str, "dd/MM/yyyy", null);
DateTime date = System.DateTime.ParseExact(str, "HH:mm:ss", null);

Listen to nirmaln - sakara - playlist audio songs at MusicMazaa.com