C# 抽象方法的协变返回类型问题

C# 抽象方法的协变返回类型问题,c#,covariance,abstract,C#,Covariance,Abstract,我正试图总结两天来对抽象方法和返回类型协方差的讨论,我已经发布了两个类似的问题,我永远感谢社区提供的信息,我只需要最后一次推动就可以到达终点。下面是我要做的:两个抽象类,招聘数据库和候选数据库,都有createra和CandidateA的具体实现。招聘数据库有一个抽象的方法来让所有被招聘的候选人返回IQueryable。我对RecruiterA的实现重写GetCandidates()方法以返回IQueryable public abstract class RecruiterBase {

我正试图总结两天来对抽象方法和返回类型协方差的讨论,我已经发布了两个类似的问题,我永远感谢社区提供的信息,我只需要最后一次推动就可以到达终点。下面是我要做的:两个抽象类,招聘数据库和候选数据库,都有createra和CandidateA的具体实现。招聘数据库有一个抽象的方法来让所有被招聘的候选人返回IQueryable。我对RecruiterA的实现重写GetCandidates()方法以返回IQueryable

public abstract class RecruiterBase
{ 
  // Constructors declared here

  public abstract IQueryable<CandidateBase> GetCandidates();
}

public abstract class CandidateBase
{  
  // Constructors declared here
}
。。。作为我解决问题的基础。所以现在我的招聘人员基础和招聘人员基础课程看起来像:

public abstract class RecruiterBase
{
  // Constructors declared here

  public IQueryable<CandidateBase> GetCandidates()
  {
     return GetCandidatesCore();
  }

  public abstract IQueryable<CandidateBase> GetCandidatesCore();
}
公共抽象类招聘数据库
{
//这里声明的构造函数
公共IQueryable GetCandidates()
{
返回GetCandidatesCore();
}
公共摘要IQueryable GetCandidatesCore();
}
我的实现

public class RecruiterA : RecruiterBase
{
  // Constructors

  protected override IQueryable<CandidateBase> GetCandidatesCore()
  {
    return GetCandidates();
  }

  public new IQueryable<CandidateA> GetCandidates()
  {
    return from candidates in db.Candidates
           select new CandidateA
           {
             CandidateId = candidates.CandidateId,
             RecruiterId = candidates.RecruiterId
           };
  }
}
公共类招聘人员时代:招聘人员基地
{
//建设者
受保护的覆盖IQueryable GetCandidatesCore()
{
返回GetCandidates();
}
公共新IQueryable GetCandidates()
{
从数据库中的候选人返回。候选人
选择新的候选茶
{
CandidateId=候选人。CandidateId,
RecruiterId=候选人。RecruiterId
};
}
}
我希望这能最终得到我想要的东西,但是我在下面的代码中遇到了一个编译时错误,因为getcandidatea()不能隐式地将CandidateA转换为CandidateBase:

  protected override IQueryable<CandidateBase> GetCandidatesCore()
  {
    return GetCandidates();
  }
受保护的覆盖IQueryable GetCandidatesCore()
{
返回GetCandidates();
}
所以我加了一个演员:

  protected override IQueryable<CandidateBase> GetCandidatesCore()
  {
    return ((IQueryable<CandidateBase>)GetCandidates());
  }
受保护的覆盖IQueryable GetCandidatesCore()
{
return((IQueryable)GetCandidates());
}
然后一切都会编译,但当我在控制器中实际调用GetCandidates()时,它会返回
IQueryable
,而不是
IQueryable
。所以我回到了我开始的地方


如果你能帮我度过难关,我会送你12包你最喜欢的啤酒

贾斯汀我有点困惑你为什么要经历那么多麻烦

如果您的抽象方法是返回类型
IQueryable
,那么这就是您将得到的结果。我不认为这有什么问题,因为稍后您仍然可以将其重新放回Candidate TEACandidateB

那么你到底想达到什么目的呢?也许我不明白你的问题

编辑以添加:

贾斯汀,这个怎么样

public abstract class RecruiterBase<T>
    {
        // Constructors declared here

        public abstract IQueryable<CandidateBase> GetCandidates();
    }

    public abstract class CandidateBase
    {
        // Constructors declared here
    }


    public class CandidateA : CandidateBase
    {

    }

    public class RecruiterA : RecruiterBase<RecruiterA>
    {
        // Constructors declared here

        // ----HERE IS WHERE I AM BREAKING DOWN----
        public override IQueryable<CandidateBase> GetCandidates()
        {
            return db.Candidates.Where(cand => cand.RecruiterId == this.RecruiterId)
                         .Select(x => new CandidateA
                                          {
                                             CandidateId = c.CandidateId,
                                             CandidateName = c.CandidateName,
                                             RecruiterId = c.RecruiterId
                                           })
                         .Cast<CandidateBase>()
                         .AsQueryable();
        }
    }
公共抽象类招聘数据库
{
//这里声明的构造函数
公共摘要IQueryable GetCandidates();
}
公共抽象类候选数据库
{
//这里声明的构造函数
}
公共类候选数据库:候选数据库
{
}
公共类招聘人员:招聘人员数据库
{
//这里声明的构造函数
//----这就是我要崩溃的地方----
公共覆盖IQueryable GetCandidates()
{
返回db.Candidates.Where(cand=>cand.createrId==this.createrId)
.选择(x=>新建)
{
CandidateId=c.CandidateId,
CandidateName=c.CandidateName,
RecruiterId=c.RecruiterId
})
.Cast()
.AsQueryable();
}
}

我认为你的意图是好的,但最终的结果是你失去了多态代码的意义,也失去了它的价值

通过对象的抽象类型或接口处理对象的目的是允许您处理任何具体的实现,而无需了解任何具体的实现细节。我认为您的信念是,通过返回具体类型,您正在生成更高质量的代码,而实际上,您正开始通过掩盖抽象来否定抽象基类的价值


一组正确构建的派生类应该只有很少的需要通过它们的具体类型来解决;抽象类应该足以处理所有实现,并且应该处理这些类的绝大多数工作——例外应该是少数。

我试图添加一个“shootmenow”标记,但我仍然是n00b:)您在控制器中使用的类型是什么?你能展示一下你在那里使用的代码吗?如果您使用RecruiterBase,您将永远不会看到变量返回CandidateA的IQueryable(此变量仅在派生类中可用)。@jeroenh,我的控制器代码非常简单:RecruiterBase recruiter=new RecruiterA();IQueryable candidates=招聘人员。GetCandidates()。。。然后添加到ViewDataStan,我的代码实现不会编译。调用“.AsQueryable();”时失败。我得到一个实例参数,即不能从IQueryable转换为IEnumerableJustin,请给我一分钟,我将复制您的代码并返回给您。Justin。公共摘要IQueryable GetCandidates();不会在您的代码示例中编译,因为CandidateBase是一个泛型类。Stan,很抱歉造成混淆。你们是对的,我有一个被标记为抽象的候选数据库,那个是从我昨天钻的一个兔子洞里出来的,但并没有成功。CandidateBase不是泛型。应该删除。斯坦,我编辑了代码以删除泛型声明。如果这让你浪费了时间,我很抱歉。但我会还原我的代码,如果它能工作并报告回来,我会尝试。我开始同意尤德的观点,我认真地质疑我的思维过程,如果我试图做的是这件不同寻常的事。在
  protected override IQueryable<CandidateBase> GetCandidatesCore()
  {
    return ((IQueryable<CandidateBase>)GetCandidates());
  }
public abstract class RecruiterBase<T>
    {
        // Constructors declared here

        public abstract IQueryable<CandidateBase> GetCandidates();
    }

    public abstract class CandidateBase
    {
        // Constructors declared here
    }


    public class CandidateA : CandidateBase
    {

    }

    public class RecruiterA : RecruiterBase<RecruiterA>
    {
        // Constructors declared here

        // ----HERE IS WHERE I AM BREAKING DOWN----
        public override IQueryable<CandidateBase> GetCandidates()
        {
            return db.Candidates.Where(cand => cand.RecruiterId == this.RecruiterId)
                         .Select(x => new CandidateA
                                          {
                                             CandidateId = c.CandidateId,
                                             CandidateName = c.CandidateName,
                                             RecruiterId = c.RecruiterId
                                           })
                         .Cast<CandidateBase>()
                         .AsQueryable();
        }
    }