2009-08-27 3 views
0

はい、これは私の四日目の抄録に関する質問です。申し訳ありませんが、私はSQLServerに関するいくつかの質問に答えて、コミュニティに好意を返すつもりです。とにかく...Linqの結果を抽象コンストラクタに投影するには?

Linqクエリの結果を抽象基本クラスコレクションに投影するにはどうすればよいですか?ここに私のRecruiterBase抽象クラスからの私の私の方法は、(対応するCandidateBase抽象クラスもある)である:

public IQueryable<CandidateBase> GetCandidates() 
{ 
    return from candidates in db.Candidates 
     where candidates.RecruiterId == this.RecruiterId 
     select candidates; 
} 

上記の方法は、暗黙的な変換が候補とCandidateBaseの間で行うことができないことを、コンパイル時にエラーがスローされます。

db.Candidates.Cast()にdb.Candidatesをコンパイルすると、すべてがコンパイルされますが、タイプがCandidateとCandidateBaseの間に強制演算子が定義されていないランタイムエラーが発生します。

私はできません:抽象を実装できないため、候補CandidateBase {...}を候補として選択してください。

また、それが再び私の抽象

アップ新しいに私を必要とするので、私は候補者と候補基地間の明示的な変換演算子を作成することができたり、私は匿名のオブジェクトに私の結果を予測し、私が得るようCandidateBaseにキャストすることができます匿名型とCandidateBase型との間の同じ実行時強制例外。

この問題はスタンRが提供する答えは、私は複雑に物事を作っていたということでした Problem with Covariant return types from an abstract method

、昨日の質問から生まれました。私は、戻って簡略化され、すべてを行ってきました(私はベースにimplmentationを残し、潜水艦からそれを削除)、そのように実装作業GetCanidates方式になってしまった:

public IQueryable<CandidateBase> GetCandidates() 
{ 
    return (from candidates in db.Candidates 
     where candidates.RecruiterId == this.RecruiterId 
     select new CandidateA 
     { 
      CandidateId = candidates.CandidateId, 
      LastName = candidates.LastName, 
      RecruiterId = candidates.RecruiterId 
     }).Cast<CandidateBase>(); 
} 

上記の方法は、コンパイルと動作し、私は」口の中で贈り物の馬を見ようとしていませんが、今では私の基底型で(私はCandidateAに結果を投影すると)私のサブタイプへの参照があり、ちょっと変わっているようです。ベースタイプ内のサブタイプへの参照が大丈夫なら、私の質問に投票してください。

ありがとうございました。

全クラスDEFS:

public abstract class RecruiterBase 
    { 
     public int RecruiterId { get; set; } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 

     public RecruiterBase() 
     { 
     } 

     public RecruiterBase(int id) 
     { 
      DataClasses1DataContext db = new DataClasses1DataContext(); 
      Recruiter rc = db.Recruiters.SingleOrDefault(r => r.RecruiterId == id); 

      this.RecruiterId = rc.RecruiterId; 
      this.FirstName = rc.FirstName; 
      this.LastName = rc.LastName; 
     } 

     public IQueryable<CandidateBase> GetCandidates() 
     { 
      DataClasses1DataContext db = new DataClasses1DataContext(); 
      return (from candidates in db.Candidates 
        where candidates.RecruiterId == this.RecruiterId 
        select new CandidateA 
        { 
         CandidateId = candidates.CandidateId, 
         LastName = candidates.LastName, 
         FirstName = candidates.FirstName, 
         RecruiterId = candidates.RecruiterId 
        } 
        ).Cast<CandidateBase>(); 
     } 
    } 



public abstract class TempCandidateBase 
    { 
     public int CandidateId { get; set; } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public int? RecruiterId { get; set; } 

     public CandidateBase() 
     { 
     } 

     public CandidateBase(int id) 
     { 
      DataClasses1DataContext db = new DataClasses1DataContext(); 

      Candidate candidate = db.Candidates.SingleOrDefault(c => c.CandidateId == id); 

      this.CandidateId = candidate.CandidateId; 
      this.FirstName = candidate.FirstName; 
      this.LastName = candidate.LastName; 
      this.RecruiterId = candidate.RecruiterId; 
     } 
    } 

public class RecruiterA : RecruiterBase 
    { 
     public RecruiterA() 
      : base() 
     { 
     } 

     public RecruiterA(int id) 
      : base(id) 
     {    
     } 
    } 


public class CandidateA : CandidateBase 
    { 
     public CandidateA() 
      : base() 
     { 
     } 

     public CandidateA(int id) 
      : base(id) 
     {    
     }   
    } 
+0

あなたは私たちに候補とCandidateBaseクラスだけでなく、実際の関連コンパイラエラーメッセージを表示してもらえますか? –

+0

私は自分の投稿を瞬時に正確なクラスのdefで編集します。 –

答えて

1

あなたは、その後、あなたの代わりに> ICandidateのIQueryable <を返すことができる候補とCandidateBase使用ICandidateインタフェースを定義する必要があるかもしれません。

0

ジャスティン、それは奇妙ではありません。それは確かに継承が意図されているものです。 CandidateBaseクラスは、候補クラスの基礎を提供します。抽象クラスであるため、後で心配する必要のないロジックを提供します。私はそれが例で説明されるほうが良いと思う。

あなたは2種類の候補クラスを持っていて、両方ともいくつかの機能を提供したいと言いますが、GetResume()と言うことができます。これに対して抽象クラスまたはインターフェイスを作成できます。あなたのケースであなたは、このような

public class CandidateBase 
{ 
    //some logic that you might need to share between Candidates 
    //such as storing Name, Age..etc 

    // your abstract method 
    public abstract String GetResume(); 
} 
として抽象クラスを作っ 今

public class CandidateA : CandidateBase 
{ 
    public String GetResume() 
    { 
     //some logic to get Resume from some web service 
     return resumeStr; 
    } 

} 

今あなたがCandidateBを持って言うことができます、あなたはディスク上のどこかに自分の履歴書を保存CandidateAは、特定のWebサービスからの彼の再開を取得し、言うことができます

。あなたがGetCandidatesを呼び出すいくつかの点で

public class CandidateB : CandidateBase 
{ 
    public String GetResume() 
    { 
     //some logic to get Resume from disk 
     return resumeStr; 
    } 

} 

あなたのコードは、()あなたはどのあなたの候補があるタイプを心配する必要はありません、あなたはまだCandidateBaseにGetResume()を呼び出すことによって、自分の履歴書を取得することができます。ところで

ジャスティンそれは本当にあなたを悩ます場合はGetCandidates(呼び出した後、あなたはいつも)バックCandidateAにキャストすることができます

IQueryable<CandidateA> candidates = recruiterClass.GetCandidates().Cast<CandidateA>(); 

ジャスティンを追加、編集、私は、これはあなたの問題を解決すべきだと思います、 お知らせ下さい。

public abstract class CandidateBase 
    { 
     public int CandidateId { get; set; } 
     public string LastName { get; set;} 
     public string FirstName { get; set;} 
     public string RecruiterId { get; set; } 

     //the rest of your logic 
    } 

public class RecruiterBase 
    { 
     // Constructors declared here 

     // ----HERE IS WHERE I AM BREAKING DOWN---- 
     public IQueryable<T> GetCandidates<T>() where T:CandidateBase, new() 
     { 

      DataClasses1DataContext db = new DataClasses1DataContext(); 
      return (from candidates in db.Candidates 
        where candidates.RecruiterId == this.RecruiterId 
        select new T() 
        { 
         CandidateId = candidates.CandidateId, 
         LastName = candidates.LastName, 
         FirstName = candidates.FirstName, 
         RecruiterId = candidates.RecruiterId 
        } 
        ) 

     } 
    } 

あなたは私は、これはすべてのそれらのキャストよりもずっときれいソリューション、だと思います:)

+0

私はあなたにスタンをフォローしていると思いますが、それは基本的にGetResumeの実装ではありません。 CandidateBaseのGetCandidates()のCandidateAへの参照で、私の基底クラスが、実装するための知識を持つ必要があるという事実がもっとあります。実際にCandidateAの実装がなければ、GetCandidate()を使って抽象クラスをコンパイルすることはできませんでした。それが何を投げているのですか。私が言ったように、私はあなたの助けをノックしていません、私は自分の無知を克服しようとしています。 –

+0

ジャスティン、ベースには実装がありません。ベースを継承するすべてのクラスが抽象メソッドを実装する必要があることを、その抽象クラスに気付く。抽象的なものを作るときには、それを継承する他のクラスが必要です。あなたの基本クラスは、CandidateAまたはCandidateBの実装が何であるかを知らず、気にもなりません。 –

+0

ああ、ジャスティン。私は最終的にあなたの問題を見始めていると思います。 Recruiterクラスに特定の候補を作成したくない場合は、それは何ですか?たとえば、募集者クラスにCandidateAを特別に作成したくない場合などです。 –

0

私は少し混乱しています...にそこに見えたこの

IQueryable<CandidateA> candidates = recruiterClass.GetCandidates<CandidateA>(); 

のようにこれを使用することができます元の質問にいくつかの編集を加えることがありますが、その編集がいつどこで行われたかははっきりしません。とにかく、何かを誤解していない限り、DataContextの候補エンティティはCandidateBaseから派生する必要があります。しかし、受け取ったエラーとそのエラーに対するあなたの解決策に基づいて、それはそうではないようです。

私はあなたの候補クラスをCandidateBaseクラスから派生させるようにマッピングを更新します。あなたのDataContextが正しく返す実際の候補エンティティはCandidateBaseクラスから派生したら、次は可能なはずです。

public IQueryable<CandidateBase> GetCandidates() 
{ 
    var candidates = from candidates in db.Candidates 
        where candidates.RecruiterId == this.RecruiterId 
        select candidates; 

    var based = candidates.Cast<CandidateBase>(); 
    return based; 
} 
+0

上記のコードは、(Linq genned)CandidatesクラスとCandidateBaseクラスからの "強制演算子が定義されていません"という例外を発生させます。 –

+0

CandidateBaseクラスから候補を派生させたい場合は、おそらく手動マッピングを行う必要があります。ビジュアルデザイナーは毎回コードを再生成し、編集内容を消去します。 POCOのアプローチを取って自分でクラスを書くと、マッピングファイルを手動で生成したり書き込んだりすると、もっと柔軟になります。上記のコードは、あなたが次のクラスを達成できる場合に可能です:public class Candidate:CandidateBase {...} – jrista

関連する問題