0

I found a very confusing issue and I Hope you can help me understanding this issue. My goal was to have struct which i can easly iterate over for readability purposes. Unfortunatly I recieved and InvalidCastException and I do not understandt why this happend. I believe the compiler should not have been able to compile it:

Originally

I expected it to work out of the box because I let the interface be implemented over a field of that struct with the help of Reshaper but I recieved a InvalidCastException when running my unittests(luckly there and not in production) trying to iterate over my field.

As I said the problem occured while iterating which means the GetEnumerator() method throws the InvalidCastException. What did I using as underlaying object which I want to iterate over? It is an ConcurrentDictionary (see code example) I found several Questions regarding the IEnumerable Interface.

And as far as i can tell regarding the implemention of that interface have done nothing wrong which is at least visibly obvious.

public struct test : IEnumerable<(int, string)>
{
        public ConcurrentDictionary<string,(int,string)> dictionary ;

        public IEnumerator<(int, string)> GetEnumerator()
        {
            return ((IEnumerable<(int,string)>)dictionary).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<(int,string)>)dictionary).GetEnumerator();
        }
}

My understanding was that ConcurrentDictionary Implements IEnumerable and therefore i should be able to simply forward these method calls. At First I thought it might has something todo with invariant/covariant type parameter

But this does not explain that behaviour to me. So I checked microsofts docu: ConcurrentDictionary and discovered my idiocy: I wanted to Iterate over my Values not the pair of keys and values.


After a lot of thoughts

I cannot get my head around why i am getting an error at Runtime if the types apparently do work out fine at compile time. It should NOT compile in the first place. What am i missing?

I have somekind of idea why if I look at this answer but were speaking about a cast of an IEnumerable with 1 generic type argument vs 2 generic type arguments. Is this difference not enough? Shouldn't this be detectable from the compiler?

ExOfDe
  • 190
  • 1
  • 12
  • 1
    Typo? `return ((IEnumerable<(int,string)>)dictionary.Values).GetEnumerator();` or actually `return dictionary.Values.GetEnumerator();` – Silvermind Feb 14 '20 at 12:44
  • 2
    dictionary implements `IEnumerable>`, dictionary values collection inherits `IEnumerable<(int, string)>` type – Pavel Anikhouski Feb 14 '20 at 12:45
  • all generic types are constructed and runtime, not at compile time. So the incorrect cast fails in runtime, it's a main reason, IMO – Pavel Anikhouski Feb 14 '20 at 13:01

0 Answers0