IDictionary, Dictionary - c#

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.

Related

Casting object to List<(Enum, string)> issue

I am creating a converter by implementing IMultiValueConverter with *Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
I am passing a List<(SomeEnumType, string)> tuple.
via MultiBinding and on the converter side I would like to cast but it throws a casting error.
I tried :
var result = (List<(Enum, string)>)values[1];
but I got this casting issue:
'Unable to cast object of type 'System.Collections.Generic.List1[System.ValueTuple2[Vasco.Basics.Contracts.CoreConfigurations.Enums.ApplicationType,System.String]]' to type 'System.Collections.Generic.List1[System.ValueTuple2[System.Enum,System.String]]'.'
It is strange because If I pass only one element of SomeEnumType and try to case like (Enum)values[1] casting works well.
When I pass a List<SomeEnumType> and try to cast like (List<Enum>)values[1] does not work already.
Thank you in advance!
When I pass a List and try to cast like (List)values1 does not work already.
You generally aren't allowed to cast generic collections like List<T> or IEnumerable<T> to other types. This comes down to how C# and the compiler handle generics and something called Covariance and contravariance. This is an incredible complicated topic, at least for me, so I won't bogg you down with the fine details.
Consider the following situation.
List<string> strings = new() { "Kitten", "Mouse", "horse" };
List<object> objs = strings;
This may seem pretty natural, especially if you try to explicitly cast the strings list such as (List<object>)strings, but this wont compile and that is a good thing! It protects you from doing silly things, like for example:
List<string> strings = new() { "Kitten", "Mouse", "horse" };
List<object> objs = strings;
objs.Add(1.29d);
this may seem like it's only tangentially related to you question, but this is really important, and is the exact reason you cant cast a collection to a different kind of collection, even if you know that they're very similar.
When we add that double to the objs list (assuming that this would compile, it doesn't), what were doing effectively is adding a double to a List<string> which would break everything about how strongly typed languages such as C# work.
It is strange because If I pass only one element of SomeEnumType and try to case like (Enum)values1 casting works well.
The reason you can do this, but not collections, is becuase with a single object the compiler can check to see if there is a valid conversion and do the conversion for you manually. Unlike with collections where the compiler, if it did the same thing as it did with single objects, it would add things to collections that may not match the type that was constrained when that collection was initialized.
Credit to John Skeet for this explanation, Ch4.4.1 ISBN 9781617294532
In general you cannot cast Lists like this - because what you are actually trying to do is cast each item in the list, rather than the list itself. Therefore you'd need to loop through and cast each item individually, like so:
var input = new List<(SomeEnumType, string)>();
// now add items to the input list
var result = new List<(Enum, string)>();
foreach (var element in input)
{
result.Add(
((Enum)element.Item1, element.Item2)
);
}
Remember, a tuple is not a single element but a wrapper for multiple elements, which each need casting.
Or, you could use a tool that allows you to 'map' types, e.g. Mapster or AutoMapper - I personally prefer Mapster.
using Mapster;
var input = new List<(SomeEnumType, string)>();
// now add items to the input list
var result = input.Adapt<List<(Enum, string)>>();
// Adapt<>() is an extension method provided by Mapster

What is the difference between declaring a class null and instantiating a class?

I am not sure if my question makes sense. But I am just wondering if there is a difference between these two lines of code:
Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();
vs
Dictionary<int, List<string>> myDictionary = null;
I know the first line instatiates a new dictionary object but since I haven't added anything into the dictionary, it's just an empty object. The second line is just an empty dictionary object. Is there a difference?
In first case:
Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();
myDictionary.Add(key,value); // NOT throw null reference exception.
In second case:
Dictionary<int, List<string>> myDictionary = null;
myDictionary.Add(key,value); // will throw null reference exception.
In order to use any collection object, you would need to create placeholder first.
Think of it as the following:
The variable is an empty paper. You may or may not write an address on it that leads you to some location.
The first line writes on the paper an address to the object (created after the new keyword).
On the second line, you just have an empty paper that is expected (by the compiler) to hold a dictionary reference at some point, but currently it is just an empty paper. So if you try to use it to go to the dictionary address, you can't (aka NullReferenceException). There is no information about where the object is (there is no address actually).
In Code:
Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();
myDictionary.Add(1, "1"); // OK, myDictionary points to an address of
// Dictionary object and I can access it.
While:
Dictionary<int, List<string>> myDictionary = null;
myDictionary.Add(1, "1"); // Fails at run-time, I have no address for a Dictionary object
// here AKA : NullReferenceException
Wrong statements you said:
You're not declaring a class null as you said, you're creating a variable pointing to null.
The second line is not an empty dictionary object as you said. It is a variable of type Dictionary that points to NULL. There is no empty dictionary object in memory.
The first line actually creates an object (memory is allocated); this means you have something to reference and act upon (for example, myDictionary.Count() will return 0). The code if (null == myDictionary) will evaluate to false.
The second line creates no object; you have a reference to nothing (and in this case, calling myDictionary.Count() will result in a NullReferenceException being thrown). The code if (null == myDictionary) will evaluate to true.
The second line is not an empty dictionary object. Try adding stuff to the 2nd dictionary object to find out yourself. Generally you point a reference to null when you actually want to assign an object to that reference later in the program.
Simple Answer, First case you can use it, Second case will give you NullReferenceException while you proceed with that, Because null means not existing So you cannot access it until it is instantiated.
There is nothing Wrong with the second declaration, but If you want to use this means you need to instantiate them(before use), Otherwise it will Throws NullReferenceException. Let PopulateDictonary() will be a method which will Return a Dictionary object then You can use this method to instantiate the myDictionary.
That is:
Dictionary<int, List<string>> myDictionary;
// Some code here, Not using myDictionary
myDictionary = PopulateDictonary();
Note :- You should check for Null before useing the myDictionary if you go with conditionaly Instantiate the object to avoid Exception.
There are many differences between the two statements, the most basic one: the first is an initialization while the latter is just a declaration. Consider the following code:
Base b = new Derived();
Towards
Base b = null;
In the first statement you create a new instance of Derived and assign it to b. Usually you need an instance of a class to call its members (for simplicity we omit the static members here), in your case the Add-method defined in Dictionary for example. By a declaration you simply define the members you may call on an instance of a class, however there is nothing said about that instance on which you call those members. So basically you need two information: the code-contract which is defined by the interface (not the OOP-meaning) you use - in your case this is just Dictionary<int, List<string>>. Now you know what you can do with an instance of this class. However you don´t have an instance of the class as long as you use the null-assignement. This is the second information - the actual instance.
To stay in my previous example how should the compiler actally know which class you actually use - Base or Derived. This will not neccessarily affect what you can do with the instance (which is given by the definition within Base), but moreover how you do it as Derived may have its own logic for doing things defined in Base.

Can't add keyValuePair directly to Dictionary

I wanted to add a KeyValuePair<T,U> to a Dictionary<T, U> and I couldn't. I have to pass the key and the value separately, which must mean the Add method has to create a new KeyValuePair object to insert, which can't be very efficient. I can't believe there isn't an Add(KeyValuePair<T, U>) overload on the Add method. Can anyone suggest a possible reason for this apparent oversight?
You can use the IDictionary<TKey,TValue> interface which provides the Add(KeyValuePair<TKey,TValue>) method:
IDictionary<int, string> dictionary = new Dictionary<int, string>();
dictionary.Add(new KeyValuePair<int,string>(0,"0"));
dictionary.Add(new KeyValuePair<int,string>(1,"1"));
Backup a minute...before going down the road of the oversight, you should establish whether creating a new KeyValuePair is really so inefficient.
First off, the Dictionary class is not internally implemented as a set of key/value pairs, but as a bunch of arrays. That aside, let's assume it was just a set of KeyValuePairs and look at efficiency.
The first thing to notice is that KeyValuePair is a structure. The real implication of that is that it has to be copied from the stack to the heap in order to be passed as a method parameter. When the KeyValuePair is added to the dictionary, it would have to be copied a second time to ensure value type semantics.
In order to pass the Key and Value as parameters, each parameter may be either a value type or a reference type. If they are value types, the performance will be very similar to the KeyValuePair route. If they are reference types, this can actually be a faster implementation since only the address needs to be passed around and very little copying has to be done. In both the best case and worst case, this option is marginally better than the KeyValuePair option due to the increased overhead of the KeyValuePair struct itself.
There is such a method – ICollection<KeyValuePair<K, T>>.Add but as it is explicitly implemented you need to cast your dictionary object to that interface to access it.
((ICollection<KeyValuePair<KeyType, ValueType>>)myDict).Add(myPair);
See
List of Explicit Interface Implementations on Dictionary<K, T>'s documentation page (you'll need to scroll down).
Explicit member implementation
The page on this method includes an example.
Should somebody really want to do this, here is an Extension
public static void Add<T, U>(this IDictionary<T, U> dic, KeyValuePair<T, U> KVP)
{
dic.Add(KVP.Key, KVP.Value);
}
but i would recommend to not do this if there is no real need to do this
Unless I'm mistaken, .NET 4.5 and 4.6 adds the ability to add a KeyValuePair to a Dictionary. (If I'm wrong, just notify me and I'll delete this answer.)
https://msdn.microsoft.com/en-us/library/cc673027%28v=vs.110%29.aspx
From the above link, the relevant piece of information is this code example:
public static void Main()
{
// Create a new dictionary of strings, with string keys, and
// access it through the generic ICollection interface. The
// generic ICollection interface views the dictionary as a
// collection of KeyValuePair objects with the same type
// arguments as the dictionary.
//
ICollection<KeyValuePair<String, String>> openWith =
new Dictionary<String, String>();
// Add some elements to the dictionary. When elements are
// added through the ICollection<T> interface, the keys
// and values must be wrapped in KeyValuePair objects.
//
openWith.Add(new KeyValuePair<String,String>("txt", "notepad.exe"));
openWith.Add(new KeyValuePair<String,String>("bmp", "paint.exe"));
openWith.Add(new KeyValuePair<String,String>("dib", "paint.exe"));
openWith.Add(new KeyValuePair<String,String>("rtf", "wordpad.exe"));
...
}
As can be seen, a new object of type Dictionary is created and called openWith. Then a new KVP object is created and added to openWith using the .Add method.
just because the enumerator for the Dictionary class returns a KeyValuePair, does not mean that is how it is implemented internally.
use IDictionary if you really need to pass KVP's because you've already got them in that format. otherwise use assignment or just use the Add method.
What would be wrong with just adding it into your project as an extension?
namespace System.Collection.Generic
{
public static class DictionaryExtensions
{
public static void AddKeyValuePair<K,V>(this IDictionary<K, V> me, KeyValuePair<K, V> other)
{
me.Add(other.Key, other.Value);
}
}
}
I'm not 100% sure, but I think the internal implementation of a Dictionary is a Hash-table, which means key's are converted to hashes to perform quick look ups.
Have a read here if you want to know more about hashtables
http://en.wikipedia.org/wiki/Hash_table

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.

Categories