I have the below example code, and I am interested to know how I can make this any cleaner, possibly through better use of SelectMany()
. At this point the QuestionList
property will not be null. All I want is a list of answerRows
that are not null
, but Questions
can sometimes be null
too.
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;
I was interested by Jon's comment about Enumerable.SelectMany
and Null.. so I wanted to try my example with some fake data to more easily see where the error is, please see the below, specifically how I am using SelectMany()
on the result of a SelectMany()
, its clearer to me now that the problem was having to make sure you don't use SelectMany()
on a null reference, obvious when I actually read the NullReferenceException
name :( and finally put things together.
Also while doing this, I realised that the use of try { } catch() { }
in this example is useless and as usual Jon Skeet has the answer :) deferred execution..
so if you want to see the exception for row 2, comment out the relevant row 1 bits :P, sorry I couldn't figure out how to stop this error without re-writing the code example.
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; } } }
survey.QuestionList .Where(l => l.Questions != null) .SelectMany(l => l.Questions) .Where(q => q != null && q.AnswerRows != null) .SelectMany(q => q.AnswerRows);
I'd recommend you ensure your collections are never null
. null
can be a bit of a nuisance if you don't handle it well. You end up with if (something != null) {}
all over your code. Then use:
survey.QuestionList .SelectMany(l => l.Questions) .SelectMany(q => q.AnswerRows);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With