Home > Enterprise >  Add subtype objects to list of supertype, then return list of subtypes from list of supertypes
Add subtype objects to list of supertype, then return list of subtypes from list of supertypes

Time:09-27

I have 3 interfaces.

public interface IItem
{
    string Name { get; set; }
}

public interface IEquipable : IItem
{
    void Equip();
}

public interface IConsumable : IItem
{
    void Use();
}

IEquipable is implemented by the classes Helmet and Bow, and IConsumable is implemented by classes Potion and Food.

Then, I have a class with a property which contains a List of IItem, and proceed to add a few items of both IEquipable and IConsumable after instantiating it.

public class Character
{
    public List<IItem> Items { get; private set; }

    public Character()
    {
        this.Items = new List<IItem>();
    }

    public void AddItem(IItem item)
    {
        this.Items.Add(item);
    }
}

Program.cs

...
Character char = new Character();
char.AddItem(new Potion());
char.AddItem(new Food());
char.AddItem(new Helmet());
char.AddItem(new Bow());
...

Is there a way I can get a List of all IEquipable members from the List of IItems, each AS IEquipable?

I want to do something like

    ...
    List<IEquipable> equipmentList = //do something to char.Items and get all items of type IEquipable.
    IEquipment equipment = equipmentList.First(...)
    equipment.Equip();
    ...

I've tried using List<IEquipable> equipmentList = char.Items.OfType<IEquipable>().ToList() but the resulting list ends up empty.

CodePudding user response:

You can use the OfType method

Filters the elements of an IEnumerable based on a specified type.

Signature

public static IEnumerable<TResult> OfType<TResult> (this IEnumerable source)

Usage

var equipable = Character.Items.OfType<IEquipable>();

Or encapsulate it as a method in the instance or an extension method if you like

CodePudding user response:

I implemented (and fixed minor typos in) your code like this:

void Main()
{
    Character character = new Character();
    character.AddItem(new Potion());
    character.AddItem(new Food());
    character.AddItem(new Helmet());
    character.AddItem(new Bow());
    
    List<IEquipable> equipmentList = character.Items.OfType<IEquipable>().ToList();
}

public class Potion : IConsumable
{
    public string Name { get; set; }

    public void Use()
    {
        throw new NotImplementedException();
    }
}

public class Food : IConsumable
{
    public string Name { get; set; }

    public void Use()
    {
        throw new NotImplementedException();
    }
}

public class Helmet : IEquipable
{
    public string Name { get; set; }

    public void Equip()
    {
        throw new NotImplementedException();
    }
}

public class Bow : IEquipable
{
    public string Name { get; set; }

    public void Equip()
    {
        throw new NotImplementedException();
    }
}

public interface IItem
{
    string Name { get; set; }
}

public interface IEquipable : IItem
{
    void Equip();
}

public interface IConsumable : IItem
{
    void Use();
}

public class Character
{
    public List<IItem> Items { get; private set; }

    public Character()
    {
        this.Items = new List<IItem>();
    }

    public void AddItem(IItem item)
    {
        this.Items.Add(item);
    }
}

Your exact code (albeit char renamed to character) works perfectly fine. The equipmentList ends up with two elements. The issue you're seeing, i.e. "the resulting list ends up empty", is not reproducible with the code you've posted.

  •  Tags:  
  • c#
  • Related