C# 泛型和强制转换-无法将继承的类强制转换为基类

C# 泛型和强制转换-无法将继承的类强制转换为基类,c#,generics,casting,C#,Generics,Casting,我知道这已经很老了,但我对这些问题还不是很了解。有人能告诉我为什么以下方法不起作用(抛出一个关于强制转换的运行时异常) 公共抽象类EntityBase{} 公共类MyEntity:EntityBase{} 公共抽象类RepositoryBase,其中T:EntityBase{} 公共类MyEntityRepository:RepositoryBase{} 现在是演员阵容: MyEntityRepository myEntityRepo = GetMyEntityRepo(); // whate

我知道这已经很老了,但我对这些问题还不是很了解。有人能告诉我为什么以下方法不起作用(抛出一个关于强制转换的
运行时
异常)

公共抽象类EntityBase{}
公共类MyEntity:EntityBase{}
公共抽象类RepositoryBase,其中T:EntityBase{}
公共类MyEntityRepository:RepositoryBase{}
现在是演员阵容:

MyEntityRepository myEntityRepo = GetMyEntityRepo(); // whatever
RepositoryBase<EntityBase> baseRepo = (RepositoryBase<EntityBase>)myEntityRepo;
MyEntityRepository myEntityRepo=GetMyEntityRepo();//无论什么
RepositoryBase-baseRepo=(RepositoryBase)myEntityRepo;
那么,有人能解释一下这是怎么无效的吗?而且,我想你没有心情解释-有没有一行代码我可以用来实际执行此转换?

RepositoryBase
不是
MyEntityRepository
的基类。您正在寻找C#中存在的有限程度的通用差异,但在这里不适用

假设您的
RepositoryBase
类有这样一个方法:

void Add(T entity) { ... }
class MyStringList : List<string> { }
现在考虑:

MyEntityRepository myEntityRepo = GetMyEntityRepo(); // whatever
RepositoryBase<EntityBase> baseRepo = (RepositoryBase<EntityBase>)myEntityRepo; 
baseRepo.Add(new OtherEntity(...));
MyEntityRepository myEntityRepo=GetMyEntityRepo();//无论什么
RepositoryBase-baseRepo=(RepositoryBase)myEntityRepo;
baseRepo.Add(新的其他实体(…);
现在,您已将不同类型的实体添加到
MyEntityReportory
。。。这不可能是对的

基本上,通用方差仅在某些情况下是安全的。特别是通用协方差(这就是您在这里描述的)只有在您仅从API中获取值时才是安全的;只有当您仅将值“输入”API时(例如,可以按面积比较任意两个形状的一般比较可以被视为正方形的比较),通用对比(反之亦然)才是安全的


在C#4中,这适用于泛型接口和泛型委托,而不是类,并且仅适用于引用类型。有关更多信息,请参阅第13章或Eric Lippert关于该主题的文章。此外,我在2010年7月的NDC上对此进行了一个小时的讨论-视频是可用的。

这需要协方差或逆变,其支持在.Net中是有限的,不能用于抽象类。不过,您可以在接口上使用variance,因此解决问题的一个可能方法是创建一个IRepository,用它代替抽象类

    public interface IRepository<out T> where T : EntityBase { //or "in" depending on the items.
    }
    public abstract class RepositoryBase<T> : IRepository<T> where T : EntityBase {
    }
    public class MyEntityRepository : RepositoryBase<MyEntity> {
    }

    ...

    IRepository<EntityBase> baseRepo = (IRepository<EntityBase>)myEntityRepo;
public interface i位置,其中T:EntityBase{//或“in”取决于项。
}
公共抽象类RepositoryBase:IRepository,其中T:EntityBase{
}
公共类MyEntityRepository:RepositoryBase{
}
...
IRepository baseRepo=(IRepository)髓鞘红细胞生成素;

每当有人问这个问题时,我都会尝试以他们为例,使用更知名的类将其翻译成显然非法的内容(这就是为什么;但我正在通过执行此翻译进一步)

让我们用MyStringList
替换MyEntityRepository
,如下所示:

void Add(T entity) { ... }
class MyStringList : List<string> { }
哦。突然,我们在一个
列表
上枚举,遇到了一个
随机
对象。那不好


希望这能让这个问题更容易理解。

我已经开始在示例中更进一步——我曾经使用字符串和对象,但在Eric Lippert的建议下,我已经开始使用真实世界的对象。。。水果/苹果/香蕉在“你不能将一个苹果添加到一堆香蕉中”这一点上效果很好。谢谢Jon的解释和链接到非常有趣的材料。我一定会考虑阅读这本书并看视频。看来你的视频链接已经坏了。我有点惊讶它仍然可用:)看看感谢大家的答案。简而言之,我现在用一个基本接口(RepositoryBase:IRepository)解决了这个问题。事实证明,我只需要在我得到的实例上执行函数,并让类本身处理其他事情。