Alternative to Dictionary with enum keys? - c#

In my solution i depend heavily on Dictionaries with an enum as a key. I find it is easy to understand and to read this construction.
One significant obstacle to the above is that it is not possible to serialize this. See Problems with Json Serialize Dictionary<Enum, Int32> for more info on this.
My question is:
Is there a equally readable and intuitive pattern for replacing the Dictionary<enunm,object> that is json serializable with the built in json serializer?
Today I have replaced a.Instance.QueryableFields[Fields.Title] with a.Instance.QueryableFields[ Fields.Title.ToString()] . Not very elegant, and it is opening up for errors.

When serializing it, just select the string value. It's not very neat, but it works.
a.Instance.QueryableFields.ToDictionary(x => x.Key.ToString(), x => x.Value)

You can easily replace a dictionary with an array here, as in C# Enums are internally saved as integers:
public enum MyEnum { Zero=0, One, Two };
object[] dictionary = new object[3];
dictionary[(int)MyEnum.Zero] = 4;
EDIT: (see comments)
You can also replace Dictionary<Enum, Object> with Dictionary<Int, Object>.

Related

Hashtable scrambling?

I have the following hashtable on my application:
System.Collections.Hashtable colunas = new System.Collections.Hashtable();
colunas.Add("Nome", "Nome");
colunas.Add("Departamento", "Departamento");
colunas.Add("Cargo", "Cargo");
After, I pass this hashtable as parameter to a function and when I pass through the hashtable in a foreach I get the following results:
Departamento
Nome
Cargo
Why the result is in that order and not in this:
Nome
Departamento
Cargo
-- EDIT --
Ok, I understood the reason, but what can I use instead of hashtable to preserve the insertion order?
Hashtables do not preserve insertion order.
Instead, they use an unspecified order based on the hashcodes of the keys.
This answer is "promoted" from a comment, by request from the Original Poster.
If it is important for you to keep the order of insertion, you might want to simply use a List<> whose elements are somehow pairs of strings. Two solutions are natural, either:
var colunas = new List<KeyValuePair<string, string>>();
colunas.Add(new KeyValuePair<string, string>("Nome", "Nome"));
colunas.Add(new KeyValuePair<string, string>("Departamento", "Departamento"));
colunas.Add(new KeyValuePair<string, string>("Cargo", "Cargo"));
or:
var colunas = new List<Tuple<string, string>>();
colunas.Add(Tuple.Create("Nome", "Nome"));
colunas.Add(Tuple.Create("Departamento", "Departamento"));
colunas.Add(Tuple.Create("Cargo", "Cargo"));
There's a technical difference between KeyValuePair<,> and Tuple<,> because the former is a struct (value type) and the latter is a class (reference type), but since both KeyValuePair<,> and Tuple<,> are immutable types, that is probably unimportant. Then decide if the property names Key/Value or Item1/Item2 are best suited for your use.
Note that if you use this solution, you don't get the benefits a hashtable offers. You don't get fast lookup on key. And there's no guarantee that the List<> can't have many entries with the same "key" string (first component of the pair). That string could even be null.
If you want to sort the List<> after all, at some point, the call colunas.Sort(); (no comparer argument given) will work for Tuple<,> (lexicographic order) but not for KeyValuePair<,>. Of course if you wanted the collection sorted all the time by keys, you would use SortedDictionary<string, string> as suggested by another answer.
Hashtable represents a collection of key/value pairs that are organized based on the hash code of the key.
but what can I use instead of hashtable to preserve the insertion order?
You have a choice:
System.Collections.Generic.SortedList<TKey, TValue>
System.Collections.Generic.SortedDictionary<TKey, TValue>
See the remarks section here for the differences.

Array with two classes

Hi im doing a school assignment, and I need to convert this JAVA code to C#
private Map<ItemID, ProductDescription> descriptions = new HashMap()<ItemID, ProductDescription>;
Is it possible to make a straight conversion?
I've already decided to make ItemID into an int, and ProductDescription is a class.
Yes, of course you can.
Please look into following examples:
IDictionary<int, string> h = new Dictionary<int, string>();
h.Add(1, "a");
h.Add(2, "b");
h.Add(3, "c");
SortedList<int, string> s = new SortedList<int, string>();
s.Add(1, "a");
s.Add(2, "b");
I think this is what you are looking for.
You could use a Dictionary<int, ProductDescription> instead.
Dictionary<TKey, TValue> Class
Represents a collection of keys and values. The key must be unique.
private Dictionary<ItemID, ProductDescription> descriptions = new Dictionary<ItemID, ProductDescription>();
The hasmap indeed allows for one null key entry. In the (rare?) case you would need this I'd simply create a special ItemID and use that for the null key.
You could ofcourse make a dictionary descendant with null key support, but that would be overdoing it imho ;-)
Yes, just replace HashMap with Dictionary. You might want to type the variable as an IDictionary (in the same spirit as the Java code), but that's not strictly necessary.
Yes, You can do the conversion using a Dictionary instead of HashMap. And of course it is more effective to get the idea of each code segment and convert. Trying to convert line by line is not recommended since you may miss a better way that can be used to resolve the problem.
There are many options.
There is an
Hashtable in C#
KeyValuePair So it can be List<KeyValuePair<T,U>>
Dictionary //Preferred
This is a good match but,
private IDictionary<ItemID, ProductDescription> descriptions
= new Dictionary<ItemID, ProductDescription>();
Note
HashMap will accept null key values, where as Dictionary will not.
If you really want to support null key values, I'd like to see you reasoning before attempting a perfect .Net HashMap implementation.

Is there a generic IDictionary implementation where IsFixedSize is True?

I wonder if there is an implementation of IDictionary interface in the standard library that has property IsFixedSize == true.
In my code, I am using a Dictionary indexed by an enum, like this:
Dictionary<EMyEnum, string> myDictionary = new Dictionary<EMyEnum, string>();
I always have values in the dictionary for all possible values of MyEnum, using a code like this:
foreach (EMyEnum myEnum in Enum.GetValues(typeof(EMyEnum)))
{
m_myDictionary.Add(myEnum, "");
}
so my dictionary actually has a fixed size. It feels kind of 'wrong' to be using Dictionary for it and I am wondering if there is perhaps a better type I am missing.
I was looking in System.Collections.Generic and System.Collections namespaces but could not find anything suitable.
In response to one of the questions, the enum is just a bunch of values, like this:
enum EMyEnum
{
meValue1,
meValue2,
meValue3
}
EDIT:
I have accepted supermem's answer as it is most to the point of the original question. To elaborate my original concern, an ordinary dictionary can have one of the keys/items deleted and then any code that relies on the fact that iterating over keys of the dictionary also iterates over all values of enum will be broken.
I understand that I can create a fixed size array but casting enums to ints is not that pretty, besides it would only work for contiguous enums (good enough in my case).
I think there is a good case for Dictionary that has enum values as keys and it is a pity that such a class does not ship with .Net.
.Net 4.5 actually introduces a new interface that sounds like it may be what you need, IReadOnlyDictionary<TKey, TValue>.
Also, IReadOnlyList<T>
No, there are no fixed size IDictionary implementations shipping with the CLR. (Except for the ReadOnly* sort, but not applicable to your problem.)
You can roll your own, but unless you have profiled this code and determined that the use of Dictionary presents a meaningful bottleneck (IMO, very rare), I'd say to keep it as is. You also have the benefit of readability as Dictionary is very well understood and easy to grok.
If you are using the simple enum declaration and not explicitly assigning values to the elements, you could use just an array:
Array values = Enum.GetValues(typeof(EMyEnum));
string[] myDictionary = new string[values.Length];
foreach (EMyEnum myEnum in values)
{
myDictionary[(int)myEnum] = "";
}
You could even wrap this approach in a custom class that treat the enum type as indexer, if you are bothered by those explicit casts to int everywhere:
class EnumDictionary<EnumType, ValueType>
{
private readonly ValueType[] array = new ValueType[Enum.GetValues(typeof(EnumType)).Length];
public ValueType this[EnumType index]
{
get { return array[Convert.ToInt32(index)]; }
set { array[Convert.ToInt32(index)] = value; }
}
}
EnumDictionary<EMyEnum, string> enumDictionary = new EnumDictionary<EMyEnum, string>();
foreach ( EMyEnum myEnum in Enum.GetValues(typeof(EnumType))
enumDictionary[myEnum] = "";
Now, if this is better than using Dictionary or not is a completely different discussion.

Dictionary Casting

Is it possible to cast an enumerated-key dictionary to an integer-key dictionary? (Or a copy constructor would work fine for what I'm doing as well.) In other words, something that looks like:
Dictionary<int, string> NewDictionary =
(Dictionary<int, string>)OldDictionary<MyEnum, string>;
(Yes, I know that syntax isn't quite correct, it's just to show what it is I'm coming from.)
You could iterate over the dictionary and build a new one, transforming each key (e.g. by using the Enumerable.ToDictionary extension) :
OldDictionary.ToDictionary(x => ((int)x.Key, x => x.Value);

IDictionary, Dictionary

I have:
IDictionary<string, IDictionary<string, IList<long>>> OldDic1;
(just for illustration purposes, it is instantiated and has values - somewhere else)
Why can I do this: ?
Dictionary<string, IDictionary<string, IList<long>>> dic1 =
OldDic1 as Dictionary<string, IDictionary<string, IList<long>>>;
Basically dic1 after executing this line has all the values from OldDic1; works.
However when I do this:
Dictionary<string, Dictionary<string, List<long>>> dic1 =
OldDic1 as Dictionary<string, Dictionary<string, List<long>>>;
I get null, it is the same as casting except it doesn't crash and instead it returns null. So the question is why I can't cast it from the interfaces to types? is there solution, other then changing how it is stored in the first place?
You can only re-cast the outermost interface/class name, not the generic parameters. The reason your second cast doesn't work is the same reason you can't cast from one array type to another even if you can cast the "contained" objects. Here's why:
List<object> objects;
List<string> strings;
objects = strings as List<object>;
// Uh oh, that's not a string!
objects.Add(42);
objects = new List<object> { "The", "answer", "is", 42 };
// Uh oh, now strings contains an integer?
strings = objects as List<string>;
The same thing would happen in your second case. You could add some kind of IDictionary to OldDic1 which is not actually a Dictionary, and then dic1 would blow up. It would have a non-Dictionary value. Ruh roh!
So, when you have containers you can change from IList<X> to List<X> and back as long as X is identical for each.
The behavior is related to the as keyword in C#. A Dictionary is not the same thing as an IDictionary.
If you were casting the other way, you may be able to get it to work in the next version of .NET which has increased support for covariance and contravariance.
The solution you might want to determine why you need to cast to the concrete Dictionary/List, and if it's required, then change the storage of the type.

Categories