Shay B.
Shay B.

Reputation: 3

Passing a generic object with type that is derived from the required type

Is it possible to pass a generic object as an argument with a class type that is derived from the expected class type?

The code below results in a compiler error, cannot convert from ItemObject<Equipment> to ItemObject<Item>, which I find odd because Equipment inherits from Item.

using System.Collections.Generic;

public abstract class Item { }

public abstract class Equipment : Item { }

public class ItemObject<T> where T : Item { }

public class EquipmentManager
{
    ItemObject<Equipment> equipment = new ItemObject<Equipment>();

    public void Unequip()
    {
        Inventory.instance.AddItem(equipment);
    }
}

public class Inventory
{
    public static Inventory instance;
    List<ItemObject<Item>> items = new List<ItemObject<Item>>();

    public void AddItem(ItemObject<Item> _item)
    {
        items.Add(_item);
    }

}

Upvotes: 0

Views: 319

Answers (2)

Adam
Adam

Reputation: 612

The problem here isn't that Equipment is inherited from Item. The issue is you are creating a specific type from a generic class. ItemObject<T>-> ItemObject<Equipment>. There is no explicit or implicit method to convert an ItemObject<Equipment> to an ItemObject<Item>.

Where the implicit conversion would work is if you had an ItemObject<Item> and tried to add an Equipment in place of an Item. In this case, the Equipment would be implicitly cast as an Item before being passed to ItemObject<Item>'s method.

Upvotes: 0

Evan Trimboli
Evan Trimboli

Reputation: 30092

You could achieve that using covariance, which would allow you to use a more derived type. However that can only be applied to interfaces, so you would need to do something like this:

public abstract class Item { }

public abstract class Equipment : Item { }

public interface IItemObject<out T> where T : Item { }
public class ItemObject<T> : IItemObject<T> where T : Item { }

public class EquipmentManager {
    IItemObject<Equipment> equipment = new ItemObject<Equipment>();

    public void Unequip() {
        Inventory.instance.AddItem(equipment);
    }
}

public class Inventory {
    public static Inventory instance;
    List<IItemObject<Item>> items = new List<IItemObject<Item>>();

    public void AddItem(IItemObject<Item> _item) {
        items.Add(_item);
    }
}

More reading on covariance and contravariance.

Upvotes: 4

Related Questions