Search code examples
c#.netdictionaryinheritancepolymorphism

Implicit casting / polymorphism with a Dictionary in C#


I've got a problem where I am not able to implicitly cast a Dictionairy<int, class> to a Dictionairy<int, interfaceOfClass> where I feel that this should normally be possible with the rules of polymorphism. The workaround I currently have is to do an explicit cast like this class => class as interfaceOfClass.

I am not sure if I am missing something in my code to make this work or if its a limitation of C#. Below is a concrete example of my problem.

namespace ImplicitCasting;

internal class Program {
    static void Main(string[] args) {
        IDictionary<int, Person> persons = new Dictionary<int, Person> {
            { 0, new Person() { Name = "Person1", Age = 20 } },
            { 1, new Person() { Name = "Person2", Age = 30 } },
            { 2, new Person() { Name = "Person3", Age = 35 } }
        };

        /*
         This doenst work
         Gives error: CS0266    Cannot implicitly convert type
         'System.Collections.Generic.IDictionary<int, ImplicitCasting.Program.Person>' to
         'System.Collections.Generic.IDictionary<int, ImplicitCasting.Program.IPerson>'.
          An explicit conversion exists (are you missing a cast?)
        */
        //IDictionary<int, IPerson> implicitCast = persons;

        // This is what I need to do to make it work
        IDictionary<int, IPerson> explictCast = persons
            .ToDictionary(entry=>entry.Key, entry=>entry.Value as IPerson);

        foreach (var enrty in explictCast) {
            Console.WriteLine($"{enrty.Key}. Person: {enrty.Value.Name}");
        }
    }

    public interface IPerson {
        string Name { get; set; }
        void DoSomething();
    }

    public class Person : IPerson {
        public string Name { get; set; } = "Test";
        public int Age { get; set; }
        public void DoSomething() {
            Console.WriteLine($"{Name} doint something");
        }
    }
}


Solution

  • In general:
    The cause for the error is that IDictionary<int, IPerson> and IDictionary<int, Person> are unrelated types, and so you cannot cast persons which is a IDictionary<int, Person> to IDictionary<int, IPerson>.

    There is also a specific issue here:
    At the moment persons is a dictionary holding objects of class Person (or any class derived from it).
    But if a cast from IDictionary<int, Person> to IDictionary<int, IPerson> would be allowed, you would then be able to add IPerson derived objects to the dictionary which are not Person (nor derived from it).
    This would break persons type safety guarantee.

    The best solution, if it's applicable for you, it to change persons to be a IDictionary<int, IPerson>. Otherwise you have to create a copy, as you already did.