必要なタイプから派生したタイプの汎用オブジェクトを渡す

2020-06-03 c# generics inheritance arguments

期待されるクラス型から派生したクラス型を使用して、汎用オブジェクトを引数として渡すことは可能ですか?

以下のコードはコンパイラエラーcannot convert from ItemObject<Equipment> to ItemObject<Item>cannot convert from ItemObject<Equipment> to ItemObject<Item> 。これは、 EquipmentItemから継承されているために奇妙に感じます。

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);
    }

}

Answers

これは、より派生した型を使用できるようにする共分散を使用して実現できます。ただし、これはインターフェースにのみ適用できるため、次のようなことを行う必要があります。

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);
    }
}

共分散と反分散の詳細については、こちらをご覧ください。

ここでの問題は、 EquipmentItemから継承されていることではありません。問題は、ジェネリッククラスから特定のタイプを作成することです。 ItemObject<T> -> ItemObject<Equipment>ItemObject<Equipment>ItemObject<Item>に変換する明示的または暗黙的なメソッドはありません。

暗黙的な変換が機能するのは、 ItemObject<Item>あり、 Item代わりにEquipmentを追加しようとした場合です。この場合、 EquipmentItemObject<Item>のメソッドに渡される前に暗黙的にItemとしてキャストされます。

Related