What collection object is appropriate for fixed ordering of values? - c#

Scenario: I am tracking several performance counters and have a CounterDescription[] correlate to DataSnapshot[]... where CounterDescription[n] describes the data loaded within DataSnapshot[n].
I want to expose an easy to use API within C# that will allow for the easy and efficient expansion of the arrays.
Simplified example (it gets more complex)
CounterDescription[0] = Humidity;
DataSnapshot[0] = .9;
CounterDescription[1] = Temp;
DataSnapshot[1] = 63;
Note how my intent is to correlate many Datasnapshots with a DateTime reference, and using the offset of the data to refer to its meaning. This was determined to be the most efficient way to store the data on the back-end, and has now reflected itself into the following structure:
public class myDataObject {
[DataMember]
public SortedDictionary<DateTime, float[]> Pages { get; set; }
/// <summary>
/// An array that identifies what each position in the array is supposed to be
/// </summary>
[DataMember]
public CounterDescription[] Counters { get; set; }
}
How will myDataObject be used?:
I will frequently search for a counter by string name, and use its' position to determine what offset a particular value will be saved. I can use an homegrown extension method to enumerate the object, or leverage the framework if ordering is guaranteed.
Also, I will need to expand each of these arrays as new sensors are added: (float[] and CounterDescription[] ), but whatever data already exists must stay in that relative offset. I don't want the serialized version of this object to confuse Temp (offset 1) with Humidity (offset 0)
Which .NET objects support this fixed ordering, expansion, and enumeration (and optional searching by string)? My guess is to use one of these objects...
Array[] , LinkedList<t>, and List<t>

Use a Dictionary<string, double> so that each name (string) maps to a value (double):
var counters = new Dictionary<string, double>();
counters["Humidity"] = 0.9;
counters["Temp"] = 63;
And use a service that gets and sets the counter values:
[OperationContract]
public double GetCounter(string name)
{
return Counters[name];
}
[OperationContract]
public void SetCounter(string name, double value)
{
Counters[name] = value;
}
You can use your CounterDescription and/or DataSnapshot classes in the same way, but make sure that the class you use as the key (probably CounterDescription) overrides Object.Equals() and Object.GetHashCode() with a proper implementation.

If CounterDescription is a string or an enum, then Dictionary seems like a good fit:
Dictionary<string, double> Counters = new Dictionary<string, double>();
// Then initialize it ...
Counters.Add("Humidity", 0);
Counters.Add("Temp", 0);
// To update:
Counters["Humidity"] = 0.9;
// To query
double humidity = Counters["Humidity"];
You can do the same sort of thing with a enum for the key, rather than a string.
If your CounterDescription type is a complex object, you can still use it as a key, but you'll need to implement IComparable or provide a comparison function.

Any list (IList) has ordered values. I always assume that mere IEnumerables have no strict order underneath; although they usually do, you can't guarantee it. I agree with the others that a Dictionary (or some other IDictionary) is a good fit.

Related

Unity enums referenced by inspector becoming out of order when extended

Issue:
enum's referenced by gameobject scripts via inspector variables become out of order when the enum has new entries added before the referenced index.
Details:
So I have multiple systems such as item lists, localisation strings, etc which are dynamically built by parsing external files. This parsing creates enum's which are used to reference the items by gameobject's via script inspector variables. Here's the parsed output by my localisation system as an example:
public enum LocaleID
{
LocalisedStrings_ENGB,
LocalisedStrings_ENUS,
//...
MAX,
}
public enum StringID
{
String_EMPTY,
String_Inventory,
String_Recipes,
String_Tools,
String_Journal,
//...
}
public static class LocalisedStrings
{
private static string[] SCLocalisedStrings_ENGB =
{
"",
"Inventory",
"Recipes",
"Tools",
"Journal",
//...
}
private static LocaleID currentLocale = (LocaleID)0;
private static string[] activeSC = SCLocalisedStrings_ENGB;
public static void SetLocale(LocaleID newLocale)
{
currentLocale = newLocale;
switch(newLocale)
{
case LocaleID.LocalisedStrings_ENGB:
activeSC = SCLocalisedStrings_ENGB;
break;
case LocaleID.LocalisedStrings_ENUS:
activeSC = SCLocalisedStrings_ENUS;
break;
}
}
//entry interface:
public static string Get(StringID stringID)
{
return activeSC[(int)stringID];
}
}
This simply returns the string via the enum index based off the set locale.
So I'd have something such as a name of an NPC exposed on a character as:
[SerializeField]
public StringID SpeakerTitle;
and set that through the inspector.
The issue is a rather obvious and expected one - if the enum is parsed differently, for example an extra entry is added to the top (for example for sorting purposes) or removed (for cleaning up obsolete entries), then all referenced enum's will become out of order by 1 spot since they'll be referencing the index of the enum entry.
A simple solution would be to impose a rule of only adding to the end and never removing entries that become stale. This becomes quite wasteful, so is obviously not very preferable.
What are suggested solutions to this issue? Any examples of how others approach this rather common situation? My preference would of course be something which could be sorted and new entries added anywhere, but we can't have everything we want :)
Just specify explicit numeric values for the entries:
public enum StringID
{
String_EMPTY = 0,
String_Inventory = 1,
String_Recipes = 2,
String_Tools = 3,
String_Journal = 4,
//...
}
That way the ordering is entirely irrelevant to the values. Note that you can do this retrospectively, or in a "just in time" way when you need to make what would otherwise be a breaking change.
(I'd personally get rid of the String_ prefix as well, but that's a different matter.)
I would use an explicit map rather than a naked array; for example:
private static Dictionary<StringID,string> SCLocalisedStrings_ENGB =
new Dictionary<StringID,string>
{
{StringID.String_EMPTY, ""},
{StringID.String_Inventory, "Inventory"},
//...
};
and get the value via something like:
string val;
return LocaleStrings.TryGetValue(key, out val) ? val : DefaultStrings[key];
Well... actually, I'd probably have the translations in external files as key/value pairs, but... meh.
Note: you could always put the dictionary data back into an ordered array; but having the explicit map prevents order from mattering.

C# - using a generic enum (or alternative method for controlling lists)

I'm writing a pathfinding algorithm for a game, but trying to keep it generic so it can be used in future applications.
I have a Node class which holds X, Y and "PassableType".
The NodeGrid class stores an array of Nodes, containing the graph information of how they connect, and then has a FindAStarPath() function, which takes as its parameters StartNode, EndNode, and params for "PassableTypes".
My problem is determining what type "PassableType" should have.
Ideally what I want is to be able to use a generic enum - i.e. a restricted list which each game defines. The Node will hold a single element of that list, to say what path type it is (the current game may use Path, Grass, Wall, etc)
Thus, when an entity tries to path, it provides the pathfinding function which types to treat as "passable". So a man may use
FindAStarPath(CurrentNode, DestinationNode, "Path", "Floor", "Door");
but a car may just use
FindAStarPath(StartNode, EndNode, "Road");
My problem is I can't work out how to get the NodeGrid to take a Generic enum or equivalent logic.
At the moment I have it taking strings, but this means I have to write
MyEnum.Road.ToString()
every time I use it.
Ideally I'd like to do something like
NodeGrid<MyEnum> CurrentNodeGrid = new NodeGrid<MyEnum>()
And then Nodes will take a MyEnum for their passableType, as will the pathfinding functions, thus allowing each game to have a different set of tile types for pathing.
But I can't define NodeGrid as:
public class NodeGrid<T> where T:enum
For clarity, the only part of the pathfinding function which uses this enum is this (contained within Node):
public bool IsPassable(string[] passableTypes)
{
for (var i = 0; i < passableTypes.Count(); i++)
{
if (this.PassableType == passableTypes[i]) return true;
}
return false;
}
Thanks
Haighstrom
Unless you're using some specific functionality of enums (like Enum.Parse), then I don't see any reason to constrain it to them. By freeing constraints, callers can use whatever types they see fit, beit enum, or a set of string values (as you currently have it), or a set of custom class instances to check against.
public class NodeGrid<T>
{
public T PassableType { get; private set; }
public bool IsPassable(params T[] passableTypes)
{
return IsPassable((IEnumerable<T>)passableTypes);
}
public bool IsPassable(IEnumerable<T> passableTypes)
{
foreach(T passType in passableTypes)
{
if (EqualityComparer<T>.Default.Equals(this.PassableType, passType))
return true;
}
return false;
}
}
But since we're now using generics, you can't use the == comparison anymore. The simplest is to leverage the EqualityComparer.Default utility. The main reason to use this over directly calling this.PassableType.Equals(passType) is it will perform null checks and leverage generics properly where applicable and if the types implement IEquatable<T>, then use those generic versions. Probably some other minor things. It will usually eventually call the Object.Equals overload.
Some examples based on your question:
//using a custom enum, calls the params T[] overload
NodeGrid<MyCarEnum> carNode = ...
carNode.IsPassable(MyCarEnum.Road, MyCarEnum.Tunnel);
//demonstrates receiving a set of pass types strings from an external source
List<string> passTypes = new List<string>("Path", "Floor", "Door");
NodeGrid<string> personNode = ...
personNode.IsPassable(passTypes) //calls the IEnumerable<T> overload
//feel free to declare enums wherever you want,
//it can avoid potential mixups like this:
NodeGrid<string> airplaneNode = ...
NodeGrid<string> personNode = ...
NodeGrid<MyCarEnum> carNode = ...
airplaneNode.IsPassable("Floor"); //makes no sense, but will compile
personNode.IsPassable("Clouds"); //makes no sense, but will compile
carNode.IsPassable("Sky"); //compile error: was expected a MyCarEnum value

Objects with many value checks c#

I want to see your ideas on a efficient way to check values of a newly serialized object.
Example I have an xml document I have serialized into an object, now I want to do value checks. First and most basic idea I can think of is to use nested if statments and checks each property, could be from one value checking that it has he correct url format, to checking another proprieties value that is a date but making sue it is in the correct range etc.
So my question is how would people do checks on all values in an object? Type checks are not important as this is already taken care of it is more to do with the value itself. It needs to be for quite large objects this is why I did not really want to use nested if statements.
Edit:
I want to achieve complete value validation on all properties in a given object.
I want to check the value it self not that it is null. I want to check the value for specific things if i have, an object with many properties one is of type string and named homepage.
I want to be able to check that the string in the in the correct URL format if not fail. This is just one example in the same object I could check that a date is in a given range if any are not I will return false or some form of fail.
I am using c# .net 4.
Try to use Fluent Validation, it is separation of concerns and configure validation out of your object
public class Validator<T>
{
List<Func<T,bool>> _verifiers = new List<Func<T, bool>>();
public void AddPropertyValidator(Func<T, bool> propValidator)
{
_verifiers.Add(propValidator);
}
public bool IsValid(T objectToValidate)
{
try {
return _verifiers.All(pv => pv(objectToValidate));
} catch(Exception) {
return false;
}
}
}
class ExampleObject {
public string Name {get; set;}
public int BirthYear { get;set;}
}
public static void Main(string[] args)
{
var validator = new Validator<ExampleObject>();
validator.AddPropertyValidator(o => !string.IsNullOrEmpty(o.Name));
validator.AddPropertyValidator(o => o.BirthYear > 1900 && o.BirthYear < DateTime.Now.Year );
validator.AddPropertyValidator(o => o.Name.Length > 3);
validator.Validate(new ExampleObject());
}
I suggest using Automapper with a ValueResolver. You can deserialize the XML into an object in a very elegant way using autommaper and check if the values you get are valid with a ValueResolver.
You can use a base ValueResolver that check for Nulls or invalid casts, and some CustomResolver's that check if the Values you get are correct.
It might not be exacly what you are looking for, but I think it's an elegant way to do it.
Check this out here: http://dannydouglass.com/2010/11/06/simplify-using-xml-data-with-automapper-and-linqtoxml
In functional languages, such as Haskell, your problem could be solved with the Maybe-monad:
The Maybe monad embodies the strategy of combining a chain of
computations that may each return Nothing by ending the chain early if
any step produces Nothing as output. It is useful when a computation
entails a sequence of steps that depend on one another, and in which
some steps may fail to return a value.
Replace Nothing with null, and the same thing applies for C#.
There are several ways to try and solve the problem, none of them are particularly pretty. If you want a runtime-validation that something is not null, you could use an AOP framework to inject null-checking code into your type. Otherwise you would really have to end up doing nested if checks for null, which is not only ugly, it will probably violate the Law of Demeter.
As a compromise, you could use a Maybe-monad like set of extension methods, which would allow you to query the object, and choose what to do in case one of the properties is null.
Have a look at this article by Dmitri Nesteruk: http://www.codeproject.com/Articles/109026/Chained-null-checks-and-the-Maybe-monad
Hope that helps.
I assume your question is: How do I efficiently check whether my object is valid?
If so, it does not matter that your object was just deserialized from some text source. If your question regards checking the object while deserializing to quickly stop deserializing if an error is found, that is another issue and you should update your question.
Validating an object efficiently is not often discussed when it comes to C# and administrative tools. The reason is that it is very quick no matter how you do it. It is more common to discuss how to do the checks in a manner that is easy to read and easily maintained.
Since your question is about efficiency, here are some ideas:
If you have a huge number of objects to be checked and performance is of key importance, you might want to change your objects into arrays of data so that they can be checked in a consistent manner. Example:
Instead of having MyObject[] MyObjects where MyObject has a lot of properties, break out each property and put them into an array like this:
int[] MyFirstProperties
float[] MySecondProperties
This way, the loop that traverses the list and checks the values, can be as quick as possible and you will not have many cache misses in the CPU cache, since you loop forward in the memory. Just be sure to use regular arrays or lists that are not implemented as linked lists, since that is likely to generate a lot of cache misses.
If you do not want to break up your objects into arrays of properties, it seems that top speed is not of interest but almost top speed. Then, your best bet is to keep your objects in a serial array and do:
.
bool wasOk = true;
foreach (MyObject obj in MyObjects)
{
if (obj.MyFirstProperty == someBadValue)
{
wasOk = false;
break;
}
if (obj.MySecondProperty == someOtherBadValue)
{
wasOk = false;
break;
}
}
This checks whether all your objects' properties are ok. I am not sure what your case really is but I think you get the point. Speed is already great when it comes to just checking properties of an object.
If you do string compares, make sure that you use x = y where possible, instead of using more sophisticated string compares, since x = y has a few quick opt outs, like if any of them is null, return, if the memory address is the same, the strings are equal and a few more clever things if I remember correctly. For any Java guy reading this, do not do this in Java!!! It will work sometimes but not always.
If I did not answer your question, you need to improve your question.
I'm not certain I understand the depth of your question but, wouldn't you just do somthing like this,
public SomeClass
{
private const string UrlValidatorRegex = "http://...
private const DateTime MinValidSomeDate = ...
private const DateTime MaxValidSomeDate = ...
public string SomeUrl { get; set; }
public DateTime SomeDate { get; set; }
...
private ValidationResult ValidateProperties()
{
var urlValidator = new RegEx(urlValidatorRegex);
if (!urlValidator.IsMatch(this.Someurl))
{
return new ValidationResult
{
IsValid = false,
Message = "SomeUrl format invalid."
};
}
if (this.SomeDate < MinValidSomeDate
|| this.SomeDate > MinValidSomeDate)
{
return new ValidationResult
{
IsValid = false,
Message = "SomeDate outside permitted bounds."
};
}
...
// Check other fields and properties here, return false on failure.
...
return new ValidationResult
{
IsValid = true,
};
}
...
private struct ValidationResult
{
public bool IsValid;
public string Message;
}
}
The exact valdiation code would vary depending on how you would like your class to work, no? Consider a property of a familar type,
public string SomeString { get; set; }
What are the valid values for this property. Both null and string.Empty may or may not be valid depending on the Class adorned with the property. There may be maximal length that should be allowed but, these details would vary by implementation.
If any suggested answer is more complicated than code above without offering an increase in performance or functionality, can it be more efficient?
Is your question actually, how can I check the values on an object without having to write much code?

Is a Dictionary's order the same if it has exactly the same content?

I know that the order of a dictionary is undefined, MSDN says so:
For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair structure representing a value and its key. The order in which the items are returned is undefined.
Thats fine, but if I have two instances of a dictionary, each with the same content, will the order be the same?
I'm guessing so because as I understand, the order is determined by the hash of the keys, and if the two dictionaries have the same keys, they have the same hashes, and therefore the same order...
... Right?
Thanks!
Andy.
No it is not guaranteed to be the same order. Imagine the scenario where you had several items in the Dictionary<TKey, TValue> with the same hash code. If they are added to the two dictionaries in different orders it will result in different orders in enumeration .
Consider for example the following (equality conforming) code
class Example
{
public char Value;
public override int GetHashCode()
{
return 1;
}
public override bool Equals(object obj)
{
return obj is Example && ((Example)obj).Value == Value;
}
public override string ToString()
{
return Value.ToString();
}
}
class Program
{
static void Main(string[] args)
{
var e1 = new Example() { Value = 'a' };
var e2 = new Example() { Value = 'b' };
var map1 = new Dictionary<Example, string>();
map1.Add(e1, "1");
map1.Add(e2, "2");
var map2 = new Dictionary<Example, string>();
map2.Add(e2, "2");
map2.Add(e1, "1");
Console.WriteLine(map1.Values.Aggregate((x, y) => x + y));
Console.WriteLine(map2.Values.Aggregate((x, y) => x + y));
}
}
The output of running this program is
12
21
Short version: No.
Long version:
[TestMethod]
public void TestDictionary()
{
Dictionary<String, Int32> d1 = new Dictionary<string, int>();
Dictionary<String, Int32> d2 = new Dictionary<string, int>();
d1.Add("555", 1);
d1.Add("abc2", 2);
d1.Add("abc3", 3);
d1.Remove("abc2");
d1.Add("abc2", 2);
d1.Add("556", 1);
d2.Add("555", 1);
d2.Add("556", 1);
d2.Add("abc2", 2);
d2.Add("abc3", 3);
foreach (var i in d1)
{
Console.WriteLine(i);
}
Console.WriteLine();
foreach (var i in d2)
{
Console.WriteLine(i);
}
}
Output:
[555, 1]
[abc2, 2]
[abc3, 3]
[556, 1]
[555, 1]
[556, 1]
[abc2, 2]
[abc3, 3]
If MSDN says its undefined you have to rely on that. The thing with undefined is it means that the implementation of the dictionary is allowed to store it in whatever order it wants. This means that a programmer should never make any assumptions about the order. I would probably assume personally without looking that the order of the elements in the dictionary would depend on the order they went in but I could be wrong. Whatever the answer is though if you are wanting some behaviour whereby the order is the same for both then you are doing it wrong.
"if the two dictionaries have the same
keys, they have the same hashes, and
therefore the same order..."
I do not think this is the case. Even if it might be true, I would not rely on this. If it's true it is an implementation detail, that might change, or be different on different implementations of the CLR or BCL (Mono comes to mind).
The Microsoft Dictionary implementation is a little complex, but from looking at the code for 5 minutes, I am willing to guess that the sequence of enumeration will be based on how the dictionary got to it's current state, including the number of resizes and insertion order.
If the spec says the order is "undefined", you can't depend on the order without explicitly ordering it. The underlying implementation may be changed at any time with a new release or service pack, just for starters. Your dictionary may be upcast from any number of concrete implementations as well.
And underlying implementation may be sensitive to the order of operations applied. Adding keys 'a', 'b' and 'c', in that order may result in a different data structure than adding the same set of keys in a different order (say, 'b','c', and 'a'). Deletions may likewise affect the data structure.
A straight binary tree, for instance, if used as the data structure behind a dictionary, if the keys are added in order, the net result is a highly unbalanced tree that is essentially a linked list. The tree will be more balance if nodes are inserted in random order.
And some data structure morph as operations are performed. If, for instance, a dictionary is implemented with the underlying data structure being a red/black tree, tree nodes will be split/rotated in order to keep the tree balanced as inserts and deletes occur. So the actual data structure then is highly dependent on the order of operations, even if the final contents are the same.
I don't know the specifics of Microsoft's implementation, but in general your assumption holds only if there are no two items in the dictionary that hash to the same value or if those entries that do collide are added in the same order.

Enum and performance

My app has a lot of different lookup values, these values don't ever change, e.g. US States. Rather than putting them into database tables, I'd like to use enums.
But, I do realize doing it this way involves having a few enums and a lot of casting from "int" and "string" to and from my enums.
Alternative, I see someone mentioned using a Dictionary<> as a lookup tables, but enum implementation seems to be cleaner.
So, I'd like to ask if keeping and passing around a lot of enums and casting them be a problem to performance or should I use the lookup tables approach, which performs better?
Edit: The casting is needed as ID to be stored in other database tables.
Casting from int to an enum is extremely cheap... it'll be faster than a dictionary lookup. Basically it's a no-op, just copying the bits into a location with a different notional type.
Parsing a string into an enum value will be somewhat slower.
I doubt that this is going to be a bottleneck for you however you do it though, to be honest... without knowing more about what you're doing, it's somewhat hard to recommendation beyond the normal "write the simplest, mode readable and maintainable code which will work, then check that it performs well enough."
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]
You could use TypeSafeEnum s
Here's a base class
Public MustInherit Class AbstractTypeSafeEnum
Private Shared ReadOnly syncroot As New Object
Private Shared masterValue As Integer = 0
Protected ReadOnly _name As String
Protected ReadOnly _value As Integer
Protected Sub New(ByVal name As String)
Me._name = name
SyncLock syncroot
masterValue += 1
Me._value = masterValue
End SyncLock
End Sub
Public ReadOnly Property value() As Integer
Get
Return _value
End Get
End Property
Public Overrides Function ToString() As String
Return _name
End Function
Public Shared Operator =(ByVal ats1 As AbstractTypeSafeEnum, ByVal ats2 As AbstractTypeSafeEnum) As Boolean
Return (ats1._value = ats2._value) And Type.Equals(ats1.GetType, ats2.GetType)
End Operator
Public Shared Operator <>(ByVal ats1 As AbstractTypeSafeEnum, ByVal ats2 As AbstractTypeSafeEnum) As Boolean
Return Not (ats1 = ats2)
End Operator
End Class
And here's an Enum :
Public NotInheritable Class EnumProcType
Inherits AbstractTypeSafeEnum
Public Shared ReadOnly CREATE As New EnumProcType("Création")
Public Shared ReadOnly MODIF As New EnumProcType("Modification")
Public Shared ReadOnly DELETE As New EnumProcType("Suppression")
Private Sub New(ByVal name As String)
MyBase.New(name)
End Sub
End Class
And it gets easier to add Internationalization.
Sorry about the fact that it's in VB and french though.
Cheers !
Alternatively you can use constants
If the question was "is casting enum faster than accessing a dictionary item?" then the other answers addressing the various aspects of the performance would make sense.
But here the question seems to be "is casting enum when I need to store their value to a database table going to negatively affect the application performance?".
If that is the case, I don't need to run any test to say that storing data in a database table is always going to be orders of magnitude slower than casting an enum or executing its ToString().
In this case I would say the important thing is readability and maintainability of the code. In simple cases enums will do the job cleanly, but I agree with other answers that dictionaries are more flexible in the long term.
Enums will greatly outperform almost anything, especially dictionary's. Enums only use single byte. But why would you be casting? Seems like you should be using the enums everywhere.
Avoid enum as you can: enums should be replaced by singletons deriving from a base class or implementing an interface.
The practice of using enum comes from an old style programming in C.
You start to use an enum for the US States, then you will need the number of inhabitants, the capitol..., and you will need a lot of big switches to get all of this infos.

Categories