2

抽象メソッドとリターンタイプの共分散について2日間のビートダウンを締めくくろうとしています。すでに、2つの同様の質問を投稿しており、提供された情報についてコミュニティに永遠に感謝しています。フィニッシュライン。これが私がやろうとしていることです。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

前の質問(抽象/仮想メソッドからの一般的な戻り型)からの提案を機能させることができなかった後、私はもっとたくさん読んで、SOで次の質問に出くわしました

C#のサブクラスのオーバーライドされたメソッドでサブタイプを返す方法は?

最終的に、私が探していたのは、リターンタイプに共分散を実装する方法であることに気づきました。MarcGravellのスニペットを使用しました...

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>の場合、それが得られます。後で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();
        }
    }
于 2009-08-26T20:47:31.707 に答える
0

あなたの意図は良いと思いますが、最終的な結果として、ポリモーフィックコードの要点が失われ、価値も失われます。

抽象型またはインターフェースによってオブジェクトを操作する目的は、具体的な実装の詳細を知らなくても、具体的な実装操作できるようにすることです。あなたの信念は、具体的な型を返すことによって、より高品質のコードを生成していると思いますが、実際には、抽象化を隠蔽して抽象基本クラスの値を否定し始めています。

適切に構築された派生クラスのセットは、具体的なタイプで対処する必要があるのはごくわずかです。抽象クラスは、すべての実装での作業に十分であり、それらのクラスでの作業の大部分を処理する必要があります。例外は少数派である必要があります。

于 2009-08-26T21:40:50.977 に答える