J'ai l'exemple de code ci-dessous, et je suis intéressé de savoir comment je peux le rendre plus propre, éventuellement grâce à une meilleure utilisation de SelectMany()
. À ce stade, la propriété QuestionList
ne sera pas nulle. Tout ce que je veux, c'est une liste de answerRows
qui ne soient pas nuls, mais Questions
peut aussi parfois être nulle.
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;
MISE À JOUR: J'ai légèrement changé mon code car mon exemple n'était pas assez clair avec l'utilisation de var
La question était plus pour m'aider à en savoir plus sur l'utilisation de LINQ.
MISE À JOUR 2:
J'ai été intéressé par le commentaire de Jon sur Enumerable.SelectMany
Et Null .. donc je voulais essayer mon exemple avec de fausses données pour voir plus facilement où est l'erreur, veuillez voir ci-dessous, en particulier comment j'utilise la fonction SelectMany()
sur le résultat d'une SelectMany()
, c'est plus clair pour moi maintenant que le problème était de s'assurer que vous n'utilisez pas SelectMany()
sur une référence nulle, évident quand je lire en fait le NullReferenceException
nom :( et enfin mettre les choses ensemble.
Également en faisant cela, j'ai réalisé que l'utilisation de try { } catch() { }
dans cet exemple est inutile et comme d'habitude Jon Skeet a réponse :) exécution différée ..
donc si vous voulez voir l'exception pour la ligne 2, commentez les bits de la ligne 1 pertinents: P, désolé, je n'ai pas pu trouver comment arrêter cette erreur sans réécrire l'exemple de code.
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);
Je vous recommande de vous assurer que vos collections ne sont jamais null
. null
peut être un peu gênant si vous ne le gérez pas bien. Vous vous retrouvez avec if (something != null) {}
partout dans votre code. Utilisez ensuite:
survey.QuestionList
.SelectMany(l => l.Questions)
.SelectMany(q => q.AnswerRows);
public static IEnumerable<TResult> SelectNotNull<TSource, TResult>(
this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
where TResult : class
{
return source.Select(selector)
.Where(sequence => sequence != null)
.SelectMany(x => x)
.Where(item => item != null);
}
Cela vous permet ensuite d'effectuer les opérations suivantes:
var allAnswers = survey.QuestionList
.SelectNotNull(list => list.Questions)
.SelectNotNull(question => question.AnswerRows);
Une solution conforme à DRY consisterait à utiliser l'opérateur de coalescence nulle ??
dans votre expression lambda SelectMany
.
IEnumerable<IQuestion> questions = survey.QuestionList.SelectMany(q => q.Questions ?? Enumerable.Empty<IQuestion>());
IEnumerable<IAnswerRow> answerRows = questions.SelectMany(q => q.AnswerRows ?? Enumerable.Empty<IAnswerRow>());
Dans le code de l'OP et dans le code ci-dessus, questions
et answerRows
ne seront jamais nuls, donc les vérifications nulles ne sont pas requises (vous souhaiterez peut-être mettre .Any()
vérifications en fonction sur votre logique métier). Mais le code ci-dessus n'entraînera également jamais d'exception si q.Questions
Ou q.AnswerRows
Est nul.