为什么此 LINQ 查询会抛出 InvalidCastException?
Why is this LINQ query throwing an InvalidCastException?
我在这一行收到 InvalidCastException:
List<Student> studentsWithSameSurname =
(List<Student>)_studentsList
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.GroupBy(j => j.FamilyID);
_studentsList
是一个 List<Student>
,所以我不知道为什么 (List<Student>
) 是无效的转换。
对于那些想要更多上下文的人,这是一个 Winforms 应用程序,我在其中将自定义 class 的通用列表序列化为 json 文件,然后在我想使用时反序列化它数据,并使用 LINQ 对其进行查询。
_studentsList
是这样定义的:
List<Student> _studentsList;
学生 class 是:
public class Student
{
public int StudentID { get; set; }
public int FamilyID { get; set; }
public bool EnrolledInAYttFM { get; set; }
public DateTime DateEnrolledOrHiatusAYttFM { get; set; }
public bool GivesBibleReading { get; set; }
public bool PresentsICRVBS { get; set; }
public bool IsHouseholder { get; set; }
public bool IsMale { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddr { get; set; }
public DateTime WeekOfLastAssignment { get; set; }
public int RecommendedNextTalkTypeID { get; set; }
public int NextCounselPoint { get; set; }
}
我想做的事情背后的逻辑是:
如果添加了一个学生,并且他们的姓氏已经存在于通用列表中,则需要确定该名字的第二个实例是否与前一个相同的家庭成员。更具体地说,如果添加 "Smith",并且他们是第一个具有该姓氏的人,他们将获得下一个可用的 familyID;否则(如果该姓氏已经输入)必须确定他们是否属于已经输入的家庭中的一个,或者他们是否是新家庭的第一个成员:
Student surNameCandidateRecord = _studentsList.SingleOrDefault(s => s.LastName == textBoxLastName.Text);
if (null == surNameCandidateRecord)
{
student.FamilyID = _studentsList.Max(x => x.FamilyID) + 1;
}
else // at least one family with that surname exists already
{
student.FamilyID = GetFamilyID();
}
GetFamilyID() 方法是抛出此异常的方法,完整内容如下:
private int GetFamilyID()
{
List<KeyValuePair<int, string>> familyIDsAndNames;
// InvalidCastException on the line below
List<Student> studentsWithSameSurname = (List<Student>)_studentsList.Where(i => i.LastName == textBoxLastName.Text.Trim()).GroupBy(j => j.FamilyID);
// </ InvalidCastException on the line above
familyIDsAndNames = new List<KeyValuePair<int, string>>();
foreach (Student s in studentsWithSameSurname)
{
string fullNameWithFamilyIdPrepended = String.Format("({0}). {1} {2}", s.FamilyID, s.FirstName, s.LastName);
familyIDsAndNames.Add(new KeyValuePair<int, string>(s.FamilyID, fullNameWithFamilyIdPrepended));
}
ChooseFamilyForm cff = new ChooseFamilyForm(familyIDsAndNames);
cff.ShowDialog();
return AYttFMConstsAndUtils.familyIDSelected;
}
在[n,re] 抛出 InvalidCastException 时,通用列表的内容是(已更改姓名和电子邮件地址以保护垃圾邮件):
[{"StudentID":1,"FamilyID":1,"EnrolledInAYttFM":true,"DateEnrolledOrHiatusAYttFM":"2016-02-12T21:52:55.9560088-08:00","GivesBibleReading":false,"PresentsICRVBS":true,"IsHouseholder":true,"IsMale":false,"FirstName":"Carly","LastName":"Shannon","EmailAddr":"carlyjeannette@att.net","WeekOfLastAssignment":"2015-08-12T21:52:50.6959113-07:00","RecommendedNextTalkTypeID":3,"NextCounselPoint":16},{"StudentID":2,"FamilyID":2,"EnrolledInAYttFM":true,"DateEnrolledOrHiatusAYttFM":"0001-01-01T00:00:00","GivesBibleReading":false,"PresentsICRVBS":true,"IsHouseholder":true,"IsMale":false,"FirstName":"Jennifer","LastName":"Volando","EmailAddr":"jenni_v@ymail.com","WeekOfLastAssignment":"0001-01-01T00:00:00","RecommendedNextTalkTypeID":0,"NextCounselPoint":0}]
...我正在尝试添加姓氏 "Volando" 的第二个人(因此将代码路由到 GetFamilyID() 方法)。
我的 LINQ 查询可能是错误的,但我不知道是哪里出错了。
更新
这是我成功使用的,基于Tordek的回答:
List<Student> studentsWithSameSurname = (List<Student>)_studentsList
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.OrderBy(j => j.FamilyID)
.ToList();
我会尽快奖励 dicho 答案;自从达到 10K,我打算做一个卡内基和 "give away" 所有点。
这一行
List<Student> studentsWithSameSurname =
(List<Student>)_studentsList
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.GroupBy(j => j.FamilyID);
你没有施法_studentsList
;你正在投射整个表情。也就是说,相当于
(List<Student>)(_studentsList
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.GroupBy(j => j.FamilyID));
而不是(如您所料)
((List<Student>)_studentsList)
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.GroupBy(j => j.FamilyID);
如果你想获得一个列表作为你的 Linq 查询的结果,你必须使用 .ToList() 方法:
studentsList
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.GroupBy(j => j.FamilyID)
.ToList();
但是,您的结果不是 List<Student>
,而是一种新类型,因为 GroupBy
方法创建了一个新的学生列表类型。 GroupBy
表达式 os 类型 IEnumerable<IGrouping<T, U>>
的结果,其中 T 是您的分组变量,U 是元素的类型;在你的例子中,它将是 IEnumerable<IGrouping<int, Student>>
,如果 FamilyID
是 int
.
类型
我在这一行收到 InvalidCastException:
List<Student> studentsWithSameSurname =
(List<Student>)_studentsList
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.GroupBy(j => j.FamilyID);
_studentsList
是一个 List<Student>
,所以我不知道为什么 (List<Student>
) 是无效的转换。
对于那些想要更多上下文的人,这是一个 Winforms 应用程序,我在其中将自定义 class 的通用列表序列化为 json 文件,然后在我想使用时反序列化它数据,并使用 LINQ 对其进行查询。
_studentsList
是这样定义的:
List<Student> _studentsList;
学生 class 是:
public class Student
{
public int StudentID { get; set; }
public int FamilyID { get; set; }
public bool EnrolledInAYttFM { get; set; }
public DateTime DateEnrolledOrHiatusAYttFM { get; set; }
public bool GivesBibleReading { get; set; }
public bool PresentsICRVBS { get; set; }
public bool IsHouseholder { get; set; }
public bool IsMale { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddr { get; set; }
public DateTime WeekOfLastAssignment { get; set; }
public int RecommendedNextTalkTypeID { get; set; }
public int NextCounselPoint { get; set; }
}
我想做的事情背后的逻辑是:
如果添加了一个学生,并且他们的姓氏已经存在于通用列表中,则需要确定该名字的第二个实例是否与前一个相同的家庭成员。更具体地说,如果添加 "Smith",并且他们是第一个具有该姓氏的人,他们将获得下一个可用的 familyID;否则(如果该姓氏已经输入)必须确定他们是否属于已经输入的家庭中的一个,或者他们是否是新家庭的第一个成员:
Student surNameCandidateRecord = _studentsList.SingleOrDefault(s => s.LastName == textBoxLastName.Text);
if (null == surNameCandidateRecord)
{
student.FamilyID = _studentsList.Max(x => x.FamilyID) + 1;
}
else // at least one family with that surname exists already
{
student.FamilyID = GetFamilyID();
}
GetFamilyID() 方法是抛出此异常的方法,完整内容如下:
private int GetFamilyID()
{
List<KeyValuePair<int, string>> familyIDsAndNames;
// InvalidCastException on the line below
List<Student> studentsWithSameSurname = (List<Student>)_studentsList.Where(i => i.LastName == textBoxLastName.Text.Trim()).GroupBy(j => j.FamilyID);
// </ InvalidCastException on the line above
familyIDsAndNames = new List<KeyValuePair<int, string>>();
foreach (Student s in studentsWithSameSurname)
{
string fullNameWithFamilyIdPrepended = String.Format("({0}). {1} {2}", s.FamilyID, s.FirstName, s.LastName);
familyIDsAndNames.Add(new KeyValuePair<int, string>(s.FamilyID, fullNameWithFamilyIdPrepended));
}
ChooseFamilyForm cff = new ChooseFamilyForm(familyIDsAndNames);
cff.ShowDialog();
return AYttFMConstsAndUtils.familyIDSelected;
}
在[n,re] 抛出 InvalidCastException 时,通用列表的内容是(已更改姓名和电子邮件地址以保护垃圾邮件):
[{"StudentID":1,"FamilyID":1,"EnrolledInAYttFM":true,"DateEnrolledOrHiatusAYttFM":"2016-02-12T21:52:55.9560088-08:00","GivesBibleReading":false,"PresentsICRVBS":true,"IsHouseholder":true,"IsMale":false,"FirstName":"Carly","LastName":"Shannon","EmailAddr":"carlyjeannette@att.net","WeekOfLastAssignment":"2015-08-12T21:52:50.6959113-07:00","RecommendedNextTalkTypeID":3,"NextCounselPoint":16},{"StudentID":2,"FamilyID":2,"EnrolledInAYttFM":true,"DateEnrolledOrHiatusAYttFM":"0001-01-01T00:00:00","GivesBibleReading":false,"PresentsICRVBS":true,"IsHouseholder":true,"IsMale":false,"FirstName":"Jennifer","LastName":"Volando","EmailAddr":"jenni_v@ymail.com","WeekOfLastAssignment":"0001-01-01T00:00:00","RecommendedNextTalkTypeID":0,"NextCounselPoint":0}]
...我正在尝试添加姓氏 "Volando" 的第二个人(因此将代码路由到 GetFamilyID() 方法)。
我的 LINQ 查询可能是错误的,但我不知道是哪里出错了。
更新
这是我成功使用的,基于Tordek的回答:
List<Student> studentsWithSameSurname = (List<Student>)_studentsList
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.OrderBy(j => j.FamilyID)
.ToList();
我会尽快奖励 dicho 答案;自从达到 10K,我打算做一个卡内基和 "give away" 所有点。
这一行
List<Student> studentsWithSameSurname =
(List<Student>)_studentsList
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.GroupBy(j => j.FamilyID);
你没有施法_studentsList
;你正在投射整个表情。也就是说,相当于
(List<Student>)(_studentsList
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.GroupBy(j => j.FamilyID));
而不是(如您所料)
((List<Student>)_studentsList)
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.GroupBy(j => j.FamilyID);
如果你想获得一个列表作为你的 Linq 查询的结果,你必须使用 .ToList() 方法:
studentsList
.Where(i => i.LastName == textBoxLastName.Text.Trim())
.GroupBy(j => j.FamilyID)
.ToList();
但是,您的结果不是 List<Student>
,而是一种新类型,因为 GroupBy
方法创建了一个新的学生列表类型。 GroupBy
表达式 os 类型 IEnumerable<IGrouping<T, U>>
的结果,其中 T 是您的分组变量,U 是元素的类型;在你的例子中,它将是 IEnumerable<IGrouping<int, Student>>
,如果 FamilyID
是 int
.