You're not going to notice a big difference in performance between the two, but I'd still recommend using a Dictionary because it will give you a little more flexibility in the future.
For one thing, an Enum in C# can't automatically have a class associated with it like in Java, so if you want to associate additional information with a state (Full Name, Capital City, Postal abbreviation, etc.), creating a UnitedState
class will make it easier to package all of that information into one collection.
Also, even though you think this value will never change, it's not perfectly immutable. You could conceivably have a new requirement to include Territories, for example. Or maybe you'll need to allow Canadian users to see the names of Canadian Provinces instead. If you treat this collection like any other collection of data (using a repository to retrieve values from it), you will later have the option to change your repository implementation to pull values from a different source (Database, Web Service, Session, etc.). Enums are much less versatile.
Edit
Regarding the performance argument: Keep in mind that you're not just casting an Enum to an int: you're also running ToString() on that enum, which adds considerable processing time. Consider the following test:
const int C = 10000;
int[] ids = new int[C];
string[] names = new string[C];
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i< C; i++)
{
var id = (i % 50) + 1;
names[i] = ((States)id).ToString();
}
sw.Stop();
Console.WriteLine("Enum: " + sw.Elapsed.TotalMilliseconds);
var namesById = Enum.GetValues(typeof(States)).Cast<States>()
.ToDictionary(s => (int) s, s => s.ToString());
sw.Restart();
for (int i = 0; i< C; i++)
{
var id = (i % 50) + 1;
names[i] = namesById[id];
}
sw.Stop();
Console.WriteLine("Dictionary: " + sw.Elapsed.TotalMilliseconds);
Results:
Enum: 26.4875
Dictionary: 0.7684
So if performance really is your primary concern, a Dictionary is definitely the way to go. However, we're talking about such fast times here that there are half a dozen other concerns I'd address before I would even care about the speed issue.
Enums in C# were not designed to provide mappings between values and strings. They were designed to provide strongly-typed constant values that you can pass around in code. The two main advantages of this are:
- You have an extra compiler-checked clue to help you avoid passing arguments in the wrong order, etc.
- Rather than putting "magical" number values (e.g. "42") in your code, you can say "States.Oklahoma", which renders your code more readable.
Unlike Java, C# does not automatically check cast values to ensure that they are valid (myState = (States)321
), so you don't get any runtime data checks on inputs without doing them manually. If you don't have code that refers to the states explicitly ("States.Oklahoma"), then you don't get any value from #2 above. That leaves us with #1 as the only real reason to use enums. If this is a good enough reason for you, then I would suggest using enums instead of ints as your key values. Then, when you need a string or some other value related to the state, perform a Dictionary lookup.
Here's how I'd do it:
public enum StateKey{
AL = 1,AK,AS,AZ,AR,CA,CO,CT,DE,DC,FM,FL,GA,GU,
HI,ID,IL,IN,IA,KS,KY,LA,ME,MH,MD,MA,MI,MN,MS,
MO,MT,NE,NV,NH,NJ,NM,NY,NC,ND,MP,OH,OK,OR,PW,
PA,PR,RI,SC,SD,TN,TX,UT,VT,VI,VA,WA,WV,WI,WY,
}
public class State
{
public StateKey Key {get;set;}
public int IntKey {get {return (int)Key;}}
public string PostalAbbreviation {get;set;}
}
public interface IStateRepository
{
State GetByKey(StateKey key);
}
public class StateRepository : IStateRepository
{
private static Dictionary<StateKey, State> _statesByKey;
static StateRepository()
{
_statesByKey = Enum.GetValues(typeof(StateKey))
.Cast<StateKey>()
.ToDictionary(k => k, k => new State {Key = k, PostalAbbreviation = k.ToString()});
}
public State GetByKey(StateKey key)
{
return _statesByKey[key];
}
}
public class Foo
{
IStateRepository _repository;
// Dependency Injection makes this class unit-testable
public Foo(IStateRepository repository)
{
_repository = repository;
}
// If you haven't learned the wonders of DI, do this:
public Foo()
{
_repository = new StateRepository();
}
public void DoSomethingWithAState(StateKey key)
{
Console.WriteLine(_repository.GetByKey(key).PostalAbbreviation);
}
}
This way:
- you get to pass around strongly-typed values that represent a state,
- your lookup gets fail-fast behavior if it is given invalid input,
- you can easily change where the actual state data resides in the future,
- you can easily add state-related data to the State class in the future,
- you can easily add new states, territories, districts, provinces, or whatever else in the future.
- getting a name from an int is still about 15 times faster than when using
Enum.ToString()
.
[grunt]