繁体   English   中英

来自抽象方法的协变量返回类型问题

[英]Problem with Covariant return types from an abstract method

我正在尝试结束为期两天的抽象方法和返回类型Covariance的失败,我已经发布了两个类似的问题,并且我非常感谢社区提供的信息,我只需要最后一推即可终点线。 这是我想要做的事情:2个抽象类RecruiterBase和CandidateBase都具有RecruiterA和CandidateA的concreate实现。 RecruiterBase有一个抽象方法来获取所有返回IQueryable的应征候选人。 我对RecruiterA的实现重写了GetCandidates()方法以返回IQueryable。

public abstract class RecruiterBase
{ 
  // Constructors declared here

  public abstract IQueryable<CandidateBase> GetCandidates();
}

public abstract class CandidateBase
{  
  // Constructors declared here
}

和实现:

public class CandidateA : CandidateBase
{
  // Constructors declared here
}

public class RecruiterA : RecruiterBase
{
  // Constructors declared here

  // ----HERE IS WHERE I AM BREAKING DOWN----
  public override IQueryable<CandidateA> GetCandidates()
  {
     return from c in db.Candidates
            where c.RecruiterId == this.RecruiterId
            select new CandidateA
            {
              CandidateId = c.CandidateId,
              CandidateName = c.CandidateName,
              RecruiterId = c.RecruiterId
            };
  }
}

尝试编译时抛出编译时错误,因为在我的RecruitreBase实现中,GetCandidates()方法返回IQueryable<CandidateA>而不是IQueryable<CandidateBase >。

在无法获得上一个问题( 抽象/虚拟方法的通用返回类型 )的建议后,我做了很多阅读,并在SO中遇到了以下问题

如何在C#中子类的重写方法中返回子类型?

最终使我意识到我一直在寻找的是一种为我的返回类型实现协方差的方法。 我用了马克·格雷夫(Marc Gravell)的片段...

abstract class BaseClass
{
    public BaseReturnType PolymorphicMethod()
    { return PolymorphicMethodCore();}

    protected abstract BaseReturnType PolymorphicMethodCore();
}

class DerivedClass : BaseClass
{
    protected override BaseReturnType PolymorphicMethodCore()
    { return PolymorphicMethod(); }

    public new DerivedReturnType PolymorphicMethod()
    { return new DerivedReturnType(); }
}

...作为我解决方案的基础。 所以现在我的RecruiterBase和RecruiterA类看起来像:

public abstract class RecruiterBase
{
  // Constructors declared here

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

  public abstract IQueryable<CandidateBase> 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
           };
  }
}

我希望最终能得到我想要的东西,但是在以下代码中出现了编译时错误,因为GetCandidates()无法将CandidateA隐式转换为CandidateBase:

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

所以我加了一个演员:

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

然后所有内容都会编译,但是当我在控制器中实际调用GetCandidates()时,它将返回IQueryable<CandidateBase>而不是IQueryable<CandidateA> 所以我就回到了我开始的地方。

如果您在整个过程中都做到了这一点,并且可以帮助我,我会给您寄12包您最喜欢的啤酒!

贾斯汀,我有点困惑为什么您需要经历所有麻烦。

如果您的抽象方法的返回类型为IQueryable<CandidateBase> ,那么您将获得该方法。 我认为这没有问题,因为以后您仍然可以将其回退到CandidateACandidateB

那么,您到底想实现什么? 也许我不明白你的问题。

编辑添加:

贾斯汀,那呢?

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();
        }
    }

我认为您的意图很好,但最终结果是您错过了多态代码的要点,并且失去了价值。

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

适当构建的一组派生类应该只需要很少的具体类型即可解决。 抽象类应足以处理所有实现,并应处理这些类的绝大多数工作-少数情况例外。

暂无
暂无

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

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