views:

282

answers:

1

I have a relationship between two base classes:

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

  public abstract IQueryable<T> GetCandidates();
}

public abstract class CandidateBase<T>
{
  // Properties declare here
  // Constructors declared here
}

And their concrete implementations as such:

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

public class RecruiterA : RecruiterBase<RecruiterA>
{
  // 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
            };
  }
}

Per MSDN documentation http://msdn.microsoft.com/en-us/library/ms379564%28VS.80%29.aspx (about half way down) and a similiar (but not identical) questoin on SO http://stackoverflow.com/questions/675857/c-specifying-the-return-type-of-an-abstract-method-from-a-base-class-according

I can make use of my concreate implementation for the return type of my overridden method GetCandidates but that is not what I want, I want to make use of the concrete implementation of a different abstract class. This is a parent/child database relationship. Is what I am trying to achieve possible? I currently get a compile time error that my GetCandidates return type does not match.

Thanks

+1  A: 

It looks like you need to define multiple generic types, with one possibly being constrained to derive from CandidateBase.

Try something like this:

public abstract class RecruiterBase<T, C> where C : CandidateBase
{
  // Properties declare here
  // Constructors declared here

  public abstract IQueryable<C> GetCandidates();
}

public abstract class CandidateBase<T>
{
  // Properties declare here
  // Constructors declared here
}

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

public class RecruiterA : RecruiterBase<RecruiterA, CandidateA>
{
  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
   };
  }
}

Edit Included Chris's correction

STW
And you beat me to it.
Chris Marisic
Won't he need public class RecruiterA : RecruiterBase<RecruiterA, CandidateA>
Chris Marisic
Crap, that was my suspicion but there are several entities in my data model such as manager->candidate, candidate->appointment, etc... So I'm going to need to define all these generic types amongst each other if I want to return strongly typed concrete implementations of my classes. It seems like that could get bloaty and unwieldy fast. I was hoping there was something I was missing.
Justin
@Chris: whoops, yup!
STW
@Justin: Yes, if you want concrete return types throughout then you'll have lots of intertwining--but could you get by without all the concrete relationships? Changing `IQueryable<T>` to `IQueryable<CandidateBase>` would let you do this--the abstract class should define a common contract for all implementatations, and you *should* be able to get by on that alone.
STW
I'm going to see if I can do that, thanks for the help.
Justin