Before I ask my question this is my structure:
public class Data : ScriptableObject {...}
public class ItemData : Data {...}
public class WeaponData : ItemData {...}
public abstract class Item<T> : Visual<T> where T : ItemData {...}
public class Weapon<T> : Item<T> where T : WeaponData {...}
I get an error (Cannot cast from source type to destination type) when I create a Weapon
object and assign it to Item<ItemData>
.
Weapon<Foo> weapon = new Weapon<Foo>();
Item<ItemData> other = weapon;
Why is that?
In C#, covariance (assigning a derived type to a base type) cannot be applied to generic classes. As a result, you would need to apply an interface specifically marked as covariant, using the out parameter modifier on a new IItem
interface.
However, that by itself isn't enough. You do not have a way to tell Item
that it will allow an instance of Weapon
to be assigned to it when Weapon
has a generic type parameter that could be anything provided it inherits from ItemData
. This places the compiler in a difficult predicament since it can't assure you that the relationship is valid. However, if you apply a new IItemData
interface to ItemData
, the cast will be permissible.
void Main()
{
Weapon<Foo> weapon = new Weapon<Foo>();
IItem<ItemData> other = weapon;
}
public interface IItem<out T> {}
public interface IItemData {}
public class Foo : WeaponData {}
public class Data : ScriptableObject {}
public class ItemData : Data, IItemData {}
public class WeaponData : ItemData {}
public abstract class Item<T> : Visual<T>, IItem<T> where T : IItemData {}
public class Weapon<T> : Item<T> where T : WeaponData {}
public class ScriptableObject {}
public class Visual<T> {}
This requires Item<T>
be updated to be constrained to IItemData
instead of constrained to a concrete type.