skip to Main Content

I have these classes

public class SubMenuItem : SubMenuVariant
{
    public string SubMenuTitle { get; set; }

    public LinkFieldType Link { get; set; }
   
    public List<SubMenuSubItem> SubItems { get; set; }
}

public class SubMenuHighlightItem : SubMenuVariant
{
    [JsonPropertyName(FieldNames.HighlightTitle)]
    public string HighlightTitle { get; set; }

    [JsonPropertyName(FieldNames.HighlightText)]
    public string HighlightText { get; set; }

    [JsonPropertyName(FieldNames.HighlightText)]
    public Link HighLightLink { get; set; }

}

public class SubMenuVariant
{
}

Which I currently store in a List<SubMenuVariant> submenu

Problem is though I am not able to access the individual properties the different menues have, since they are being casted to a SubMenuVariant, which don’t have any properties.

The list can only contain one type, at no point will both types exist in the list. The items is not being added explicitly to the list, but is being created by JsonSerializer.Deserialize a json request, which contains the properties, to the baseclass.

So the json can either look like this:

{
   "submenu": [
   {
    "SubMenuTitle " : "Title", 
    "Link" : "Link", 
    "SubItems" : [
       {...}
    ]   
   }
   ]
}  

Or

 {
   "submenu": [
   {
    "HighlightTitle " : "Title", 
    "HighlightLink" : "Link", 
    "HighlightText" : "Text"
   }
   ]
} 

Is it somehow possible to store different class types in the same list?

3

Answers


  1. No, your solution is as good as it gets. The only other – worse – option being List<object>.

    Login or Signup to reply.
  2. Your issue is not that you can’t store different types derived from the same base class. Your problem is accessing the members of the run-time types of the objects. That requires a cast. You can conditionally cast the items as you get them out of the list:

    foreach (var smv in submenu)
    {
        var smi = smv as SubMenuItem;
    
        if (smi != null)
        {
            // ...
        }
        else
        {
            var smhi = smv as SubMenuHighlightItem;
    
            if (smhi != null)
            {
                // ...
            }
        }
    }
    

    In newer versions of C#, you can use pattern-matching:

    foreach (var smv in submenu)
    {
        if (smv is SubMenuItem smi)
        {
            // ...
        }
        else if (smv is SubMenuHighlightItem smhi)
        {
            // ...
        }
    }
    

    Here’s an example of the pattern-matching option in action:

    class Program
    {
        static void Main(string[] args)
        {
            var items = new List<BaseType>();
    
            items.Add(new FirstDerivedType { FirstName = "One" });
            items.Add(new SecondDerivedType { SecondName = "Two" });
            items.Add(new FirstDerivedType { FirstName = "Three" });
            items.Add(new SecondDerivedType { SecondName = "Four" });
    
            foreach (var bt in items)
            {
                if (bt is FirstDerivedType fdt)
                {
                    Console.WriteLine(fdt.FirstName);
                }
                else if (bt is SecondDerivedType sdt)
                {
                    Console.WriteLine(sdt.SecondName);
                }
            }
        }
    }
    
    public class FirstDerivedType : BaseType
    {
        public string FirstName { get; set; }
    }
    
    public class SecondDerivedType : BaseType
    {
        public string SecondName { get; set; }
    }
    
    public class BaseType
    {
    }
    
    Login or Signup to reply.
  3. You can also try reflection, if you know the property name you can
    access it as follows:

     internal class Program
    {
        static void Main(string[] args)
        {
            List<SubMenuVariant> variants = new List<SubMenuVariant>();
    
            variants.Add(new Sub1() { Title = "Test" });
            variants.Add(new Sub2());
    
    
            var prop = variants.First().GetType().GetProperty("Title");
    
            prop?.GetValue(variants.First(), null);
    
    
        }
    
    }
    public class Sub1 :SubMenuVariant
    {
        public string Title { get; set; }   
    }
    
    public class Sub2: SubMenuVariant
    {
        public int Index { get; set; }
    }
    public class SubMenuVariant
    {
    }
    

    This will generate the following result:
    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search