将类从asType转换为类<t,m>:无法强制转换

时间:2018-03-06 10:33:36

标签: c# casting

我正在尝试将我使用asType()的对象转换为它的父类。

这是我的结构(我认为不需要细节,只是类描述和继承)

    public class Entity1: Entity
    {}
    public class Entity2: Entity
    {}
public class Entity
    {}

public class ClassM1 : MigrationBaseReverse<Entity1, Entity2>
    {}

public class MigrationBaseReverse<T, M> : MigrationBase<T, M>
        where T : Entity, new()
        where M : Entity, new()  
    {}

 public class MigrationBase<T, M>
        where M : Entity, new()
        where T : Entity, new()
    {}

我的所作所为:

我像这样存储了ClassM1的类型信息(ti是一个TypeInfo):

Type type = ti.AsType();

然后,我使用Activator

创建一个新实例
instance = Activator.CreateInstance(type);

然后我(或者直接在Activator中,但得到了相同的结果),尝试将它像这样投射它的父母

instance as MigrationBase<Entity, Entity>

但这不起作用,我得到了null,而这显然有效

instance as MigrationBase<Entity1, Entity2>

当Entity1和Entity2从实体继承时,我会认为我可以使用实体,但似乎不是。

我也试过这样的演员:

(MigrationBase<Entity1, Entity2>) instance 

但我在演员阵容中遇到错误:

Unable to cast object of type 'ClassM1' to type 'MigrationBase`2[Entity,Entity]'.

我应该补充一点,我尝试了所有使用MigrationBaseReverse

的演员表

任何想法都会受到赞赏。

我不确定标题,因为解释起来很复杂,所以如果一个人知道一个更好的标题,那么就不要害怕编辑。

我希望你能得到所有需要的信息。

1 个答案:

答案 0 :(得分:4)

这个问题每周在SO上被问到1000次。

首先,c#中的泛型类型差异仅允许在接口和委托上使用。你没有。

其次,为了允许类型差异,您必须证明它是安全的。 IList<string> IList<object>,因为转换根本不安全; IList<T>中的T 不变

IEnumerable<string> IEnumerable<object>,因为IEnumerable<out T>T协变

使用您提供的代码,无法确定理论IMigrationBase<T, M>TM中是否可以协变。如果它可以,那么您的转换将起作用,如果它不能,那么它就不会。

关于这个主题的非常有用的读物​​:Covariance and Contravariance in C# series。一定要阅读第六部分。

更新:

好的,想象一下你的理论IMigrationBase<T, M>看起来像这样:

interface IMigrationBase<T, M>
    where T: Entity
    where M: Entity
{
    M Migrate(T entity) { .... }
}

想象一下这是合法的:

var m1 = new ClassM1();
IMigrationBase<Entity, Entity> m = m1; //illegal but lets play along

然后我们可能有以下可怕的想法:

m.Migrate(new Entity3()); //Legal but ouch!

现在m,真正m1,突然尝试迁移它一无所知的Entity3类型。发生这种情况是因为界面在TM中的协变而在T中的协变)中不协变,转换永远不会是安全的。如果你想要类型方差,这个理论界面的真实声明将是IMigrationBase<in T, out M>,以下转换是安全的:

IMigrationBase<Entity1, Entity> m = m1;

如果您的界面在TM中是协变的,那么您尝试的转换将是安全的。如何知道TM中的协变性?好吧,拇指规则(不是100%准确,但大部分时间都足够好),TM应该只是接口的输出(out)成员,从不输入(in)。如果你的接口需要使用它的一个泛型类型作为输入,那么它在泛型类型参数中永远不会是协变的。