Search code examples
c#dictionaryradixderived

Storing derived classes in a base class Dictionary


I am trying to create a scene or state manager which stores a Dictionary for each state as a way to load or change the state of the program (for example, a Main Menu state and a Game state). I have a bunch of derived classes of base class State that have variables that are not included in the base State class. Am I able to safely store them in this Dictionary? Will I have any data loss? If this doesn't work, what are alternative methods to achieve my goal?


Solution

  • This seems like something you could easily test yourself. But just for the fun of it, suppose you have a base class like:

    public class Base
    {
        public string Name
        {
            get;
            set;
        }
    
        public override string ToString()
        {
            return Name;
        }
    }
    

    And a derived class like:

    public class Derived : Base
    {
        public string Description
        {
            get;
            set;
        }
    
        public override string ToString()
        {
            return base.ToString() + " - " + Description;
        }
    }
    

    Then you can create a setup like this:

    Base baseObject = new Base{ Name = "Base"};
    Derived derivedObject = new Derived { Name = "Derived", Description = "Description" };
    
    Dictionary<int, Base> dictionary = new Dictionary<int, Base>();
    dictionary.Add(1, baseObject);
    dictionary.Add(2, derivedObject);
    

    Now you can run a little test to see, if any information is lost:

    foreach (Base value in dictionary.Values)
    {
        Console.WriteLine(value.ToString());
    }
    

    As you can see, not only is the correct overridden ToString() called, but it also still has the right value for the Description property. So no, you don't "lose" anything. But as long as it is a base type, you can only access the base properties directly.

    Btw. you can also check, if a value really is a certain derived type:

    foreach (Base value in dictionary.Values)
    {
        if (value is Derived)
        {
            Console.WriteLine("{0} is Derived", value.Name);
            // trying to access value.Description at this point
            // would cause a compiler error "Cannot resolve symbol".
        }
        else
        {
            Console.WriteLine("{0} is not Derived", value.Name);
        }
    }
    

    And with as and a check for null, you can "safely" (i.e. without exception caused by direct casting for example) get the value in the "full" derived type, where you can access all the additional properties again:

    foreach (Base value in dictionary.Values)
    {
        Derived derived = value as Derived;
        if (derived != null)
        {
            Console.WriteLine("{0} is Derived and has Description: {1}",
                               derived.Name, derived.Description);
            // now that derived actually is of type Derived,
            // accessing derived.Description is perfectly fine.
        }
    }