-1

I am trying to make a dictionary of lists of derived objects. My solution was to use classes for each object that implemented the same base interface. The issue is that interface must have the property of the list of the object its designated to contain. That property must allow me to store each one of the derived classes without data loss from the objects.

I've tried down casting the lists and putting them straight into the dictionaries. I've tried making wrapper classes and down casting the base property to the proper list also.

public class Body
{
   Dictionary<string, List<BodyPart>> parts;

   public Body(List<Arms> arms_, List<Head> head_) //etc
   {
       parts = new Dictionary<string, List<BodyPart>>()
       {
           {"arms", arms_},
           {"head", head_}
           //etc
       }
   }
}

problem with this solution is that the lists of specific derived body parts will not cast to a list of the base class BodyPart. The other issue is that I'm also certain that because this is down casting it will cause data loss as I will only be able to reference the objects as the base class.

I expect the result to be a dictionary of different body parts that I can reference without data loss.

  • Are classes `Arms` and `Head` derived from `BodyPart`? If yes you are almost there. You just need to case the list by yourself: `{"arms", arms_.Cast().ToList()},` – Fabjan Jul 28 '19 at 17:05
  • The derived classes must be declared like this `public class Head : BodyPart { ... }`. Note that even then a `List` is not assignment compatible to `List` but a `Head` is assignment compatible to `BodyPart`. – Olivier Jacot-Descombes Jul 28 '19 at 17:08
  • Could you just use ```object```? Of course it creates a headache when you actually want to use the value, i.e. ```if (obj is Head) ... else if (obj is Arms)``` – joelc Jul 28 '19 at 17:39

2 Answers2

0

You must convert the lists

Dictionary<string, List<BodyPart>> parts;

public Body(List<Arms> arms_, List<Head> head_) //etc
{
    parts = new Dictionary<string, List<BodyPart>>()
    {
        {"arms", new List<BodyPart>(arms_)},
        {"head", new List<BodyPart>(head_)}
        //etc
    }
}

The reason is this: assume that you could insert a List<Head> into the dictionary. Then you retrieve it with

List<BodyPart> bodyParts = parts["head"];

and add it arms

bodyParts.Add(new Arms()); // Oops! this is a List<Head>.

Therefore a List<Derived> is not assignment compatible to a List<Parent>. Maybe it would just be simpler to type all these lists as List<BodyPart>, even when they contain Arms and Heads.

This new List<BodyPart>(head_) woks, because the constructor accepts an IEnumerable<BodyPart> as parameter. An IEnumerable<T> is read-only. Therefore the list (which implements IEnumerable<Head>) you pass as argument will only be read and its elements will be added to a List<BodyPart>, which is okay.

See: Covariance and Contravariance (C#)

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
-1

Try something like this :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<BodyPart> arms = new List<BodyPart>() { new BodyPart() { name = "Left Arm" }, new BodyPart() { name = "Right Arm" } };
            List<BodyPart> head = new List<BodyPart>() { new BodyPart() { name = "Head" } };
            new Body(arms, head);
        }
    }
    public class Body
    {
        Dictionary<string, List<BodyPart>> parts = new Dictionary<string, List<BodyPart>>();

        public Body(List<BodyPart> arms_, List<BodyPart> head_) //etc
        {
            parts.Add("arms", arms_);
            parts.Add("head", head_);
        }
    }
    public class BodyPart
    {
        public string name { get; set; }
    }

}
jdweng
  • 33,250
  • 2
  • 15
  • 20