2

我正在尝试结束对抽象方法和返回类型协方差的两天抨击,我已经发布了两个类似的问题,我永远感谢社区提供的信息,我只需要最后一次推动即可终点线。这是我想要做的: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 包你最喜欢的啤酒!

4

2 回答 2

1

贾斯汀 我有点困惑为什么你需要经历所有这些麻烦。

如果您的抽象方法是返回类型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();
        }
    }
于 2009-08-26T20:47:31.707 回答
0

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

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

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

于 2009-08-26T21:40:50.977 回答