简体   繁体   中英

How to create extension methods with lambda expressions

Currently i am creating an extension method that accepts parameters. Using the below example, how could one convert this using lambda expressions?

public static decimal ChangePercentage(this IEnumerable<Trade> trades, DateTime startDate, DateTime endDate)
{
    var query = from trade in trades
                where trade.TradeTime >= startDate
                where trade.TradeTime <= endDate
                orderby trade.TradeTime descending
                select trade;
    return (query.First().Value - query.Last().Value) / query.First().Value * 100;
}

What are the pro/cons using lambda vs normal method parameters?

Thanks

One way you could change the sample to use lambda expressions is to use a filter.

public static decimal ChangePercentage(this IEnumerable<Trade> trades, 
                                       Func<Trade,bool> pred)
        {
            var query = from trade in trades
                        where pred(trade);
                        orderby trade.TradeTime descending
                        select trade;
            return (query.First().Value - query.Last().Value) / query.First().Value * 100;
        }

    someTrades.ChangePercentage(x => x.TradeDate >= startDate && x.TradeTime <= endDate);

The biggest pro this gives you is flexbility. Instead of having a method which does date based filtering for calculation. You have a method with a flexible filter method for calculating percentages.

Did you want to replace the startDate and endDate parameters with a single lambda expression?

public static decimal ChangePercentage(this IEnumerable<Trade> trades, DateTime startDate, DateTime endDate)
{
    return trades.ChangePercentage(trade => trade.TradeTime >= startDate 
        && trade.TradeTime <= endDate);
}

public static decimal ChangePercentage(this IEnumerable<Trade> trades, Func<Trade, bool> filter)
    {
        var query = from trade in trades
                    where filter(trade)
                    orderby trade.TradeTime descending
                    select trade;
        return (query.First().Value - query.Last().Value) / query.First().Value * 100;
    }

Your method is implicitly using lambda expressions already.

When you say

trade.TradeTime >= startDate

What you're really saying is "given a Trade called " trade ", return a bool by evaluating the following: trade.TradeTime >= startDate ."

That is the definition of this lambda expression:

Func<Trade, bool> expr = (trade => trade.TradeTime >= startDate);

And in fact, minus the declaration of expr , this is how you would express it if you were using the function composition syntax for LINQ instead of the query syntax.

If you don't want parameters, you can move the filtering outside.

public static decimal ChangePercentage(this IEnumerable<Trade> trades)
{
  var query = trades.OrderByDescending(t => t.TradeTime);

  if (query.Any())
    return (query.First().Value - query.Last().Value) / query.First().Value * 100;
  else
    return 0;
}

Then, it can be called like this:

DateTime startDate, DateTime endDate

decimal answer = ChangePercentage
(
  from trade in trades
  where trade.TradeTime >= startDate
  where trade.TradeTime <= endDate
  select trade
);

Continuing on Tim's answer , you could also provide a lambda to perform the calculation:

    public static decimal ChangePercentage(
        this IEnumerable<Trade> trades, 
        Func<Trade, bool> filter, 
        Func<Trade, Trade, decimal> calc)
    {
        var query = from trade in trades
                    where filter(trade)
                    orderby trade.TradeTime descending
                    select trade;
        return calc(query.First(), query.Last());
    }

Usage:

    trades.ChangePercentage(
        trade => (trade.TradeTime >= startDate && trade.TradeTime <= endDate), 
        (t1, t2) => (t1.Value - t2.Value) / t1.Value * 100
    ); 

It's important to understand that Lambda expressions serve a different purpose than extension methods. Lambda expressions are used primarily as a compact syntax for defining a delegate implementation or function implementaion. An added benefit of lambda expressions is that you can define event handlers and functions within the body of another function, useful if you have a simple function that is used only within a specific method. Just define the function using the Func<> or Action<> type with lamda syntax.

I would recommend picking up a copy of Jon Skeet's C# In Depth. It covers these topics in detail.

Here's this function as a lambda expression

private void Form1_Load(object sender, EventArgs e)
        {
            //signature of our function
            Func<IEnumerable<Trade>, DateTime, DateTime, decimal> changePercentage = null;

            //function implemented using lambda expression syntax
            changePercentage += (trades, startDate, endDate) => 
            {
                var query = from trade in trades
                            where trade.TradeTime >= startDate
                            where trade.TradeTime <= endDate
                            orderby trade.TradeTime
                            descending
                            select trade;
                return (query.First().Value - query.Last().Value) / query.First().Value * 100;
            };
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM