Inizializzatori di oggetti in una query LINQ: è possibile riutilizzare i dati calcolati?
-
27-10-2019 - |
Domanda
Sto usando una query linq che sembra (dopo qualche semplificazione) qualcosa di simile al seguente:
List<UserExams> listUserExams = GetUserExams();
var examData =
from userExam in listUserExams
group by userExam.ExamID into groupExams
select new ExamData()
{
ExamID = groupExams.Key,
AverageGrade = groupExams.Average(e => e.Grade),
PassedUsersNum = groupExams.Count(e => /* Some long and complicated calculation */),
CompletionRate = 100 * groupExams.Count(e => /* The same long and complicated calculation */) / TotalUsersNum
};
Quello che mi preoccupa è l'espressione di calcolo che appare due volte, per PassedUsersNum e CompletionRate.
Supponendo che CompletionRate = (PassedUsersNum / TotalUsersNum) * 100
, come posso scriverlo riutilizzando il calcolo di PassedUsersNum, invece di scrivere di nuovo quell'espressione?
Soluzione
Il modo più semplice sarebbe utilizzare let
per inserire prima un altro passaggio di selezione:
List<UserExams> listUserExams = GetUserExams();
var examData =
from userExam in listUserExams
group by userExam.ExamID into groupExams
let passCount = groupExams.Count( /* long expression */)
select new ExamData()
{
ExamID = groupExams.Key,
AverageGrade = groupExams.Average(e => e.Grade),
PassedUsersNum = passCount,
CompletionRate = 100 * passCount / TotalUsersNum
};
L'espressione verrà valutata solo una volta per gruppo, ovviamente.
Altri suggerimenti
Puoi anche semplicemente estrarre il tuo Count func in un altro metodo che restituisce un Func se vuoi, o un metodo che accetta un double e restituisce un bool.
List<UserExams> listUserExams = GetUserExams();
var examData =
from userExam in listUserExams
group by userExam.ExamID into groupExams
select new ExamData()
{
ExamID = groupExams.Key,
AverageGrade = groupExams.Average(funcMethod()),
PassedUsersNum = groupExams.Count(e => traditionalMethod(e)),
CompletionRate = 100 * groupExams.Count(e => /* The same long and complicated calculation */) / TotalUsersNum
};
// later...
private Func<double,bool> funcMethod(){ return e=> /* your calculation */ }
private bool traditionalMethod(double d){ return /* your calculation */ }