Question

Je suis en train de terminer un deux jours tapait sur les méthodes abstraites et type de retour Covariance, je l'ai déjà posté deux questions semblables et je suis éternellement reconnaissant à la communauté pour les informations fournies, il me faut une dernière poussée pour se rendre à la ligne d'arrivée. Voici ce que je suis en train de faire: 2 classes abstraites, RecruiterBase et CandidateBase, les deux ont mises en œuvre ConCreate de RecruiterA et CandidateA. RecruiterBase a une méthode abstraite pour obtenir tous les candidats recrutés retour IQueryable. Ma mise en œuvre de RecruiterA remplace la méthode GetCandidates () pour retourner IQueryable.

public abstract class RecruiterBase
{ 
  // Constructors declared here

  public abstract IQueryable<CandidateBase> GetCandidates();
}

public abstract class CandidateBase
{  
  // Constructors declared here
}

et les mises en œuvre:

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

Tentative de complile qui jettent une erreur de compilation parce que dans ma mise en œuvre de RecruitreBase la méthode renvoie GetCandidates () IQueryable<CandidateA> au lieu de IQueryable<CandidateBase>.

Après ne pas être en mesure d'obtenir les suggestions d'une question précédente ( retour générique types de méthodes abstraites / virtuelles ) pour travailler, je fait beaucoup plus de lecture, et suis tombé sur la question suivante dans SO

Comment revenir sous-type de méthode surchargée de la sous-classe en C #?

Ce qui m'a finalement fait réaliser ce que je cherchais depuis était un moyen de mettre en œuvre Covariance pour mon type de retour. J'ai utilisé extrait de 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(); }
}

... comme base pour ma solution. Alors maintenant, mes cours RecruiterBase et RecruiterA ressemblent:

public abstract class RecruiterBase
{
  // Constructors declared here

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

  public abstract IQueryable<CandidateBase> GetCandidatesCore();
}

et ma mise en œuvre ...

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

J'espérais que cela m'a finalement obtenir ce que je cherchais, mais je suis une erreur de compilation dans le code suivant, car GetCandidates () ne peut pas convertir implicitement CandidateA à CandidateBase:

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

alors j'ai ajouté un casting:

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

Tout compile ensuite, mais quand je l'appelle en fait GetCandidates () dans mon contrôleur retourne IQueryable<CandidateBase> au lieu de IQueryable<CandidateA>. Je suis donc de retour où j'ai commencé.

Si vous avez fait tout le chemin à travers cela et vous pouvez me aider je vais vous envoyer un paquet 12 de votre bière préférée!

Était-ce utile?

La solution

Justin Je suis un peu confus pourquoi vous avez besoin de passer par tout ce problème.

Si vous méthode abstraite est de type retour IQueryable<CandidateBase> alors c'est ce que vous obtiendrez. Je ne vois pas de problème avec cela, car plus tard vous pouvez toujours jeter de nouveau à CandidateA ou CandidateB

Alors, qu'est-ce que vous essayez d'atteindre exactement? Peut-être que je ne vous comprends des questions.

Modifier pour ajouter:

Justin, qu'en est-ce?

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

Autres conseils

Je pense que vos intentions sont bonnes, mais le résultat net est que vous manque le point code polymorphique et de perdre aussi la valeur.

Le but de travailler avec des objets par leur type abstrait ou par leurs interfaces est de vous permettre de travailler avec tous mise en œuvre concrète, sans avoir besoin de connaître tous les détails de mise en œuvre en béton . Je pense que votre croyance est que, en renvoyant des types concrets que vous produisez code de meilleure qualité, alors qu'en fait, vous commencez à nier la valeur de la classe de base abstraite en couvrant l'abstraction.

Un ensemble bien construit des classes dérivées devrait avoir que très peu de besoins à satisfaire par leurs types concrets; la classe abstraite devrait suffire pour travailler avec toutes les implémentations et doit gérer la grande majorité des travaux avec ces classes -. les exceptions doivent être dans la minorité

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top