【发布时间】:2013-01-22 22:23:00
【问题描述】:
我有下面的示例代码,我很想知道如何让这个更干净,可能通过更好地使用SelectMany()。此时QuestionList 属性不会为空。我想要的只是answerRows 的列表,它们不是null,但Questions 有时也可以是null。
IEnumerable<IQuestion> questions = survey.QuestionList
.Where(q => q.Questions != null)
.SelectMany(q => q.Questions);
if(questions == null)
return null;
IEnumerable<IAnswerRow> answerRows = questions
.Where(q => q.AnswerRows != null)
.SelectMany(q => q.AnswerRows);
if(answerRows == null)
return null;
我对 Jon 关于 Enumerable.SelectMany 和 Null 的评论很感兴趣。
所以我想用一些假数据来尝试我的例子,以便更容易地看到错误在哪里,请看下面,特别是我如何在SelectMany() 的结果上使用SelectMany(),现在问题对我来说更清楚了必须确保您不要在空引用上使用SelectMany(),当我实际阅读NullReferenceException 名称时很明显:( 最后将它们放在一起。
在执行此操作时,我意识到在此示例中使用 try { } catch() { } 是无用的,并且像往常一样 Jon Skeet 具有 answer :) 延迟执行..
因此,如果您想查看第 2 行的异常,请注释掉相关的第 1 行位:P,抱歉,如果不重新编写代码示例,我无法弄清楚如何停止此错误。
using System;
using System.Collections.Generic;
using System.Linq;
namespace SelectManyExample
{
class Program
{
static void Main(string[] args)
{
var questionGroupList1 = new List<QuestionGroup>() {
new QuestionGroup() {
Questions = new List<Question>() {
new Question() {
AnswerRows = new List<AnswerRow>() {
new AnswerRow(),
new AnswerRow()
}
},
// empty question, causes cascading SelectMany to throw a NullReferenceException
null,
new Question() {
AnswerRows = new List<AnswerRow>() {
new AnswerRow() {
Answers = new List<Answer>() {
new Answer(),
new Answer()
}
}
}
}
}
}
};
var questionGroupList2 = new List<QuestionGroup>() {
null,
new QuestionGroup()
};
IEnumerable<AnswerRow> answerRows1 = null;
IEnumerable<AnswerRow> answerRows2 = null;
try
{
answerRows1 = questionGroupList1
.SelectMany(q => q.Questions)
.SelectMany(q => q.AnswerRows);
}
catch(Exception e) {
Console.WriteLine("row 1 error = " + e.Message);
}
try
{
answerRows2 = questionGroupList2
.SelectMany(q => q.Questions)
.SelectMany(q => q.AnswerRows);
}
catch (Exception e)
{
Console.WriteLine("row 2 error = " + e.Message);
}
Console.WriteLine("row 1: " + answerRows1.Count());
Console.WriteLine("row 2: " + answerRows2.Count());
Console.ReadLine();
}
}
public class QuestionGroup {
public IEnumerable<Question> Questions { get; set; }
}
public class Question {
public IEnumerable<AnswerRow> AnswerRows { get; set; }
}
public class AnswerRow {
public IEnumerable<Answer> Answers { get; set; }
}
public class Answer {
public string Name { get; set; }
}
}
【问题讨论】:
-
为什么你认为你的收藏永远是空的?
-
questions和answerRows永远不能是null。在合理的设计中,q.Questions和q.AnswerRows可能也不应该是null。 -
@Jon 解释为什么它们永远不能为空。如果
QuestionList是长度为 1 的List<Type>,我没有理由想阻止QuestionList[0]为空。同样,我的示例中的“类型”仍然可以未初始化属性“问题”。即null. -
@flem 它们永远不能为空,因为
Where和SelectMany就是这样工作的。如果输入为空,则抛出异常,如果不为空,则结果将是项目序列或空序列。它永远不会是null。作为一条规则,您应该避免使用null值作为集合或序列,而只需使用空集合。 -
@flem:
questions是Enumerable.SelectMany或Queryable.SelectMany决定返回的任何内容。并且保证不为空。
标签: c# linq .net-4.0 linq-to-objects