7

I'm just messing around with some data types of C# in order to understand them. I've been trying for a while to understand why this dictionary is turned into a KeyValuePair. Here's my code:

class Program
{
    static Dictionary<string, int> operatii(int a, int b)
    {
        Dictionary<string, int> calculare = new Dictionary<string, int>();
        calculare.Add("suma", a + b);
        calculare.Add("produs", a * b);
        return calculare;
    }

    static void Main(string[] args)
    {
        foreach(Dictionary<string, int> dict in operatii(5, 6))
        {
            Console.WriteLine();
        }
    }
}

And I'm getting this error:

Error CS0030 Cannot convert type 'System.Collections.Generic.KeyValuePair<string, int>' to 'System.Collections.Generic.Dictionary<string, int>'

Now as I'm writing this I've understood that my logic was flawed, and the first parameter of the foreach cannot be a Dictionary.

But how does C# know that this should've been a KeyValuePair? Maybe I really meant to write Dictionary in there, and make the foreach run only once (because I only have one Dictionary).

Thanks.

Stefan
  • 17,448
  • 11
  • 60
  • 79
  • `foreach(Dictionary dict in operatii(5, 6))` When you loop through a `List` - every entry in it isn't a `List`. It is an `int`. The exact same principle applies to `Dictionary`. The entries aren't dictionaries. They are keyvaluepairs. – mjwills Oct 10 '20 at 12:21
  • `Maybe I really meant to write Dictionary in there, and make the foreach run only once (because I only have one Dictionary).` Maybe that is your _intent_ but it won't work. Looping doesn't work like that. If I loop through a box of apples, I am looping through the apples one by one. I can't decide to get a box (rather than an individual apple) instead. That doesn't make sense, loop-wise. – mjwills Oct 10 '20 at 12:22
  • Thanks to you both for your answers. –  Oct 11 '20 at 13:44

3 Answers3

5

You are calling the enumerator of the Dictionary by calling foreach - and the foreach will give you access to the elements.

This is by design; see msdn.

foreach (var element in enumerable)

The compiler is trying to tell you that you're trying to squeeze the whole dictionary in a single element: the Key ValuePair. (note; this is an analogy: the actual reason is about type mismatch, not about size. C# is type safe which means you can only assign something to a type which has the same - possibly through inheritance - type)

Similar as if you foreach over an int[] array, the element in the loop will be an int, and not the array itself, int[].

So, for your code:

Your method is of type Dictionary<>:

//the Dictionary is enumerable 
//an element is the KeyValuePair
Dictionary<string, int> operatii(int a, int b)

So, in the loop:

//  this should be an element    in    the enumeratable
foreach(Dictionary<string, int> dict in operatii(5, 6))

Or its equivalent:

var array = new int[] {1,2,3};

// element is of type ìnt`
foreach(int element in array)

To fix it:

foreach(KeyValuePair<string, int> dict in operatii(5, 6))
Stefan
  • 17,448
  • 11
  • 60
  • 79
  • Great answer, thanks for your time. So each data type has a GetEnumerator method, which will tell the compiler what each element of the loop will be? For example, for a Tuple, how will the compiler know which data type to use? –  Oct 11 '20 at 13:46
  • Hi, not all data types have it - its about having the IEnumerable interface implemented. Most lists, collections and array have it. The Tuple doesn't I believe. Here is a list. https://learn.microsoft.com/en-us/dotnet/api/system.collections.ienumerable?view=netcore-3.1 – Stefan Oct 11 '20 at 14:01
3

But how does C# know that this should've been a KeyValuePair?

Because Dictionary has a GetEnumerator method, and the foreach loop knows to use this method. The method represents a collection of KeyValuePair<TKey, TValue>, hence the compiler can generate the message.

Maybe I really meant to write Dictionary in there, and make the foreach run only once (because I only have one Dictionary).

Then you should have your method return a collection of dictionaries, not a single dictionary. Such as e.g. static List<Dictionary<string, int>> operatii(int a, int b).

GSerg
  • 76,472
  • 17
  • 159
  • 346
0

A foreach lets you execute code for each separate element in the list. So it unpacks the dictionary into a sequence of key-value pairs.

See the other answers for more details

Hans Kesting
  • 38,117
  • 9
  • 79
  • 111