0

Hello ive to following code. I know T will be always a type from the base class "Item". But i cant cast the List to Item. For T item its working.

private List<Item> activeItemList;
private Item activeItem;


public void StartBuildingSystem<T>(List<T> itemList, T item, int count, string name) where T : Item
{
    UiPlacementActivate(itemList, item,count);
    PlacingAreas(GetActiveBluePrint(name), GetActiveType(itemList, name));
    activeBuildingType = GetActiveBuildingType(name);
    activeItem = item;
    //activeItemList = itemList;//
}

The code in // // doesnt work as i cant cast a List T to List Item. Any better approach? If i know the incoming List will be always from the base class "Item" but its coming from diffrent inventorys(Cooling, Secruity,....) or is there a way i can cast the List easy to Item List like it works for T item to Item.

  • Could you post the exact errors you get? It's a bit difficult to see it without knowing the exact signatures off all the methods you are using ... In general you could probably use [Linq `Cast`](https://learn.microsoft.com/dotnet/api/system.linq.enumerable.cast) – derHugo May 04 '21 at 15:36
  • Look up covariance in C# -- tons of SO posts and other articles about it – canton7 May 04 '21 at 15:37

4 Answers4

2

You can't cast between lists of various types because a List<T> is invariant. See still confused about covariance for more (or check out the 3,000 questions on Stackoverflow about it).

Instead of casting, you can convert the list (by casting its items one at a time). So instead of

activeItemList = itemList;

use

activeItemList = itemList.Select( x => (Item)x ).ToList();
John Wu
  • 50,556
  • 8
  • 44
  • 80
1

If you can make the following change in your code, it will allow covariance:

private IEnumerable<Item> activeItemList; // previously List<Item>
private Item activeItem;

public void StartBuildingSystem<T>(List<T> itemList, T item, int count, string name) where T : Item
{
    UiPlacementActivate(itemList, item,count);
    PlacingAreas(GetActiveBluePrint(name), GetActiveType(itemList, name));
    activeBuildingType = GetActiveBuildingType(name);
    activeItem = item;
    activeItemList = itemList; //it will now work
}
1

Mutable collections cannot implement variance. To understand why, see the following example based on your code:

private List<Fruit> currentFruitList;
private Fruit currentFruit;


public void StartBuildingSystem<T>(List<T> fruitList, T fruit) where T : Fruit
{
    currentFruit = fruit;
    currentFruitList = fruitList;
}

Let's imagine for a moment that the above code compiles (it won't). Now imagine you do this:

List<Apple> apples = new();
Apple apple = new();

StartBuildingSystem(apples, apple);

Orange orange = new();
currentFruit = orange; //fine!
currentFruitList.Add(new Orange()); //this is a problem!

Immutable collections, however, can handle this. To extend this example, if you change your List<Fruit> to an IEnumerable<Fruit> everything will compile just fine as you cannot accidentally add an orange to an IEnumerable<Apple>

This is one of the better articles Microsoft has to offer on the subject.

joelmdev
  • 11,083
  • 10
  • 65
  • 89
0

John's answer looks like it would work, but this is an alternative:

// add "using System.Linq;" beforehand
activeItemList = itemList.Cast<Item>().ToList();

The other answers explain this as well, but basically, activeItemList cannot be assigned to a List which is of a strict subtype (say BlueItem) of Item, because then, this List will be more "limited" and not be able to handle other non-overlapping subtypes of Item (e.g. RedItem).

ELinda
  • 2,658
  • 1
  • 10
  • 9