Инициализаторы объектов в запросе LINQ - возможно ли повторно использовать вычисленные данные? - PullRequest
4 голосов
/ 13 июня 2011

Я использую запрос linq, который выглядит (после некоторого упрощения) примерно так:

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
};

Меня беспокоит то, что выражение вычисления, которое появляется дважды, для PassedUsersNum и CompletionRate.

Предполагая, что CompletionRate = (PassedUsersNum / TotalUsersNum) * 100, как я могу написать это, повторно используя вычисление PassedUsersNum, вместо того, чтобы снова писать это выражение?

Ответы [ 2 ]

6 голосов
/ 13 июня 2011

Самый простой способ - использовать let, чтобы сначала ввести другой шаг выбора:

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
    };

Выражение будет оцениваться только один раз для группы, конечно.

1 голос
/ 13 июня 2011

Вы также можете просто извлечь вашу функцию Count в другой метод, который возвращает Func, если хотите, или метод, который принимает значение double и возвращает 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 */ }
...