Joe
Joe

Reputation:

Can I call a function in a lambda expression?

I would like to do the following but I don't think this will work:

.OrderByDescending(s => Score(s)), ...


private double Score(Story s)
        {
            DateTime now = DateTime.Now;
            TimeSpan elapsed = now.Subtract(s.PostedOn);
            double daysAgo = elapsed.TotalDays;

            return s.Votes.Count + s.Comments.Count - daysAgo;
        }

a. should this work? b. if not, do I need to query for the stories and then sort them by the score?

Upvotes: 8

Views: 8956

Answers (2)

flq
flq

Reputation: 22859

On a minor note, you may write

.OrderByDescending(Score)

since "Score"'s signature fulfills the required signature.

Upvotes: 2

Marc Gravell
Marc Gravell

Reputation: 1064114

Yes, that should work if the sequence is a sequence of Story items; what problem are you having? Note that if Score doesn't apply to any instance, it might be worth making it static.

Another option is to make the Score() method an instance method on a Story, or an extension method.

Note that this only applies to LINQ-to-Objects; if you are using LINQ-to-SQL / LINQ-to-Entities, etc you either need to use a lambda for the whole thing, or (in LINQ-to-SQL only) use a UDF-mapped function (on the data-context) to calculate the value.

Example (LINQ-to-Objects) with your original syntax:

using System.Linq;
using System;
class Story { // declare type
    public DateTime PostedOn { get; set; }
    // simplified purely for convenience
    public int VotesCount { get; set; }
    public int CommentsCount { get; set; }
}
static class Program {
    static void Main() {
        // dummy data
        var data = new[] {
            new Story { PostedOn = DateTime.Today,
                VotesCount = 1, CommentsCount = 2},
            new Story { PostedOn = DateTime.Today.AddDays(-1),
                VotesCount = 5, CommentsCount = 22},
            new Story { PostedOn = DateTime.Today.AddDays(-2),
                VotesCount = 2, CommentsCount = 0}
        };
        var ordered = data.OrderByDescending(s=>Score(s));
        foreach (var row in ordered)
        {
            Console.WriteLine(row.PostedOn);
        }
    }

    private static double Score(Story s) {
        DateTime now = DateTime.Now;
        TimeSpan elapsed = now.Subtract(s.PostedOn);
        double daysAgo = elapsed.TotalDays;
        // simplified purely for convenience
        return s.VotesCount + s.CommentsCount - daysAgo;
    }
}

Add a this (i.e. Score(this Story s)), and you can use:

.OrderByDescending(s=>s.Score())

Upvotes: 5

Related Questions