0

はい、アブストラクトに関する質問をするのはこれで 4 日目です。申し訳ありませんが、SQLServer に関するいくつかの質問に答えて、コミュニティに恩返しをしようと思います。ともかく...

Linq クエリの結果を抽象基本クラス コレクションに射影するにはどうすればよいですか? これは、私の RecruiterBase 抽象クラスからのメソッドです (対応する CandidateBase 抽象クラスもあります)。

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

上記のメソッドは、Candidate と CandidateBase の間で暗黙的な変換を行うことができないというコンパイル時エラーをスローします。

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

できません: 抽象を実装できないため、CandidateBase として New CandidateBase { ... } を選択します。

Candidate と Candidate ベースの間に明示的な変換演算子を作成することもできません。

また、匿名型と CandidateBase 型の間で同じランタイム強制例外が発生するため、結果を匿名オブジェクトに投影してから CandidateBase にキャストすることもできません。

この問題は、昨日の質問、 抽象メソッドからの共変の戻り値に関する問題から生じました。

スタン R の答えは、私が物事を複雑にしているというものでした。私は戻って、すべてを単純化し(実装をベースに残し、サブから削除しました)、そのように実装された動作する 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 に射影するとき)、それは奇妙に思えます。基本タイプ内からのサブタイプへの参照が問題ない場合は、私の質問に投票してください。

ありがとう。

完全なクラス定義:

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)
        {            
        }        
    }
4

3 に答える 3

1

Candidate と CandidateBase が使用する ICandidate インターフェイスを定義する必要がある場合は、代わりに IQueryable< ICandidate> を返すことができます。

于 2009-08-27T18:43:06.913 に答える
0

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

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

CandidateAが特定のWebサービスから履歴書を取得するとします

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

}

ここで、CandidateBがあり、彼の履歴書をディスクのどこかに保存するとします。

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

}

GetCandidates()を呼び出すときのある時点で、候補者のタイプを気にする必要はありません。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
                    }
                    )

        }
    }

あなたはこのようにこれを使うことができます

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

これは、これらすべてのキャストよりもはるかにクリーンなソリューションだと思います:)

于 2009-08-27T18:56:13.343 に答える
0

私は少し混乱しています...元の質問にいくつかの編集があったようですが、それらの編集がいつ/どこで行われたかは明確ではありません。とにかく、私が何かを誤解していない限り、DataContextのCandidateエンティティはCandidateBaseから派生する必要があります。ただし、受け取っているエラーとそのエラーの解決策に基づいて、それを行っているようには見えません。

マッピングを更新して、CandidateクラスがCandidateBaseクラスから派生するようにします。DataContextが返す実際のCandidateエンティティが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;
}
于 2009-08-27T19:03:10.257 に答える