简体   繁体   English

C#将派生的泛型类型转换为父类

[英]C# casting derived generic type to parent

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对象并将其分配给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. 在C#中,协方差(将派生类型分配给基类型)不能应用于泛型类。 As a result, you would need to apply an interface specifically marked as covariant, using the out parameter modifier on a new IItem interface. 因此,您需要在新的IItem接口上使用out参数修饰符来应用专门标记为协变的接口。

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 . 你没有办法告诉Item ,它将使实例Weapon将被分配给它当Weapon有可能是任何东西 ,只要它从继承的泛型类型参数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. 但是,如果将新的IItemData接口应用于ItemData ,则允许使用IItemData转换。

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. 这需要将Item<T>更新为约束到IItemData而不是约束到具体类型。

Generics get all weird when you deal with this kind of stuff. 当你处理这类东西时,泛型会变得奇怪。 I've not investigated this in C#, but if it's anything like Java - which I suspect it is - you can only set a variable of a given generic type if the generic parameters match. 我没有在C#中对此进行过调查,但如果它像Java一样 - 我怀疑它是 - 如果泛型参数匹配,则只能设置给定泛型类型的变量。 For example, other would have to be an Item of type Foo ( Item<Foo> ), not of type ItemData . 例如,其他必须是Foo类型的Item( Item<Foo> ),而不是ItemData类型。 The reason goes something like this: 原因是这样的:

class A {...}
class B : A {...}
class C {
    public static void main(string[] args) {
        List<B> BL = new List<B>();
        List<A> AL = BL;
        AL.Add(new A()); // Now the List of B instances has an A instance in it!!
    }
}

I'm not sure if there's a way to do something like Java's List<? extends A> 我不确定是否有办法像Java的List<? extends A> List<? extends A> in C#, though. 但是,在C#中List<? extends A> That would be the Java-type solution. 这将是Java类型的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM