Domanda

Sto cercando di concludere una due giorni picchiava sui metodi astratti e restituire il tipo di covarianza, ho già postato due domande simili e sono eternamente grato alla comunità per le informazioni fornite, ho solo bisogno di un'ultima spinta per arrivare al traguardo. Ecco quello che sto cercando di fare: 2 classi astratte, RecruiterBase e CandidateBase, entrambi hanno le implementazioni Concreate di RecruiterA e CandidateA. RecruiterBase ha un metodo astratto per ottenere tutti i candidati reclutati ritorno IQueryable. Il mio attuazione RecruiterA ridefinisce il metodo GetCandidates () per restituire IQueryable.

public abstract class RecruiterBase
{ 
  // Constructors declared here

  public abstract IQueryable<CandidateBase> GetCandidates();
}

public abstract class CandidateBase
{  
  // Constructors declared here
}

e le implementazioni:

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

Il tentativo di complile che lanciare un errore di compilazione perché nel mio attuazione RecruitreBase le GetCandidates () restituisce IQueryable<CandidateA> invece di IQueryable<CandidateBase>.

Dopo non essere in grado di ottenere i suggerimenti da una domanda precedente ( tipi di metodi astratti / virtuali ) al lavoro, ho fatto un sacco di più la lettura, ed ho trovato la seguente questione nel SO

modalità di restituzione sottotipo di metodo override di sottoclasse in C #?

che alla fine mi ha fatto capire quello che avevo cercato per era un modo per implementare covarianza per il mio tipo di ritorno. Ho usato frammento di 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(); }
}

... come base per la mia soluzione. Così ora le mie classi RecruiterBase e RecruiterA assomigliano:

public abstract class RecruiterBase
{
  // Constructors declared here

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

  public abstract IQueryable<CandidateBase> GetCandidatesCore();
}

e la mia implementazione ...

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

Speravo che sarebbe finalmente mi ottenere quello che stavo cercando, ma ho ottenuto un errore di compilazione nel codice seguente perché GetCandidates () non può convertire implicitamente CandidateA a CandidateBase:

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

Così ho aggiunto un cast:

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

Il tutto poi compila ma quando ho effettivamente chiamo GetCandidates () nel mio controller restituisce IQueryable<CandidateBase> invece di IQueryable<CandidateA>. Quindi io sono terzino destro dove ho iniziato.

Se hai fatto tutto il percorso attraverso questo e tu mi possa aiutare Ti mando un pacchetto di 12 la vostra birra preferita!

È stato utile?

Soluzione

Justin Sono un po 'confuso perché è necessario passare attraverso tutte le difficoltà.

Se metodo astratto è di tipo ritorno IQueryable<CandidateBase> , quindi questo è quello che si otterrà. Non vedo un problema con questo, dal momento che in seguito si potrebbe ancora lanciare di nuovo a CandidateA o CandidateB

Così che cosa esattamente stai cercando di raggiungere? Forse non sono la comprensione si mette in discussione.

Modifica per aggiungere:

Justin, che dire di questo?

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

Altri suggerimenti

Credo che le vostre intenzioni sono buone, ma il risultato netto è che vi state perdendo il punto di codice polimorfico e anche di perdere il valore.

Lo scopo di lavorare con gli oggetti in base al tipo astratto o di loro interfacce è quello di consentire di lavorare con qualsiasi di implementazione concreta, senza dover conoscere qualsiasi concreti dettagli di implementazione . Credo che la vostra convinzione è che con il ritorno tipi concreti si stanno producendo il codice di qualità superiore, quando in realtà si sta cominciando a negare il valore della classe di base astratta coprendo l'astrazione.

Un insieme correttamente integrato di classi derivate dovrebbe avere solo poche esigenze essere affrontate dai loro tipi concreti; la classe astratta dovrebbe essere sufficiente per lavorare con tutte le implementazioni e deve gestire la maggior parte del lavoro con quelle classi -. le eccezioni dovrebbero essere in minoranza

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top