来自抽象方法的Covariant返回类型的问题

时间:2009-08-26 20:35:42

标签: c# covariance abstract

我正试图结束两天的抽象方法和返回类型协方差,我已经发布了两个类似的问题,我永远感谢社区提供的信息,我只需要最后一次推送到达终点线。以下是我要做的事情:2个抽象类,RecruiterBase和CandidateBase,都有RecruiterA和CandidateA的混合实现。 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&gt;。

在无法获得上一个问题(Generic return types from abstract/virtual methods)的建议后,我做了很多阅读,并在SO中遇到了以下问题

How to return subtype in overridden method of subclass in C#?

最终让我意识到我一直在寻找的是一种为我的返回类型实现Covariance的方法。我使用了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包你最喜欢的啤酒!

2 个答案:

答案 0 :(得分:1)

Justin我有点困惑为什么你需要解决所有麻烦。

如果抽象方法的返回类型为 IQueryable<CandidateBase> ,那么这就是你得到的。我没有看到这个问题,因为稍后您仍然可以将其转回 CandidateA CandidateB

那你究竟想要实现什么目标?也许我不理解你的问题。

编辑以添加:

贾斯汀,这个怎么样?

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

答案 1 :(得分:0)

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

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

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