是的,这是我连续第四天询问关于摘要的问题,对不起,我会尝试回答一些关于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类型之间没有定义强制运算符。
我不能这样做:选择New CandidateBase {...}作为CandidateBase,因为摘要无法实现。
我也不能在候选人和候选人基础之间创建一个显式转换运算符,因为它会再次要求我新建我的摘要
我也无法将结果投射到匿名对象中,然后在匿名类型和CandidateBase类型之间获得相同的运行时强制异常时转换为CandidateBase。
这个问题来自昨天的问题, Problem with Covariant return types from an abstract method
Stan 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中时)看起来很奇怪如果对基类型中的子类型的引用是可以的,请随意向我投票。
感谢。
全班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 :(得分:1)
您可能需要定义Candidate和CandidateBase使用的ICandidate接口,然后您可以返回IQueryable&lt; ICandidate&GT;代替。
答案 1 :(得分:0)
贾斯汀,这并不奇怪......这确实是继承的目的。您的CandidateBase类为您的候选类提供了一个基础,因为它是抽象的,这意味着它提供了一些您以后不必担心的逻辑。我认为用一个例子可以更好地解释。
假设你有两个不同的候选类,他们都想提供一些功能,比如说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()获得他们的简历。
顺便说一下Justin,如果它真的困扰你,你可以在调用GetCandidates()
之后再回到CandidateAIQueryable<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>();
我认为这是一个比所有Casts更清晰的解决方案:)
答案 2 :(得分:0)
我有点困惑......似乎对原始问题进行了一些编辑,但是这些编辑的时间/地点尚不清楚。无论如何,除非我误解了某些内容,否则DataContext中的候选实体应该来自CandidateBase。但是,根据您收到的错误以及您对该错误的解决方案,它似乎没有这样做。
我会更新你的映射,使你的Candidate类派生自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;
}