Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Fun with Func<T,TResult> Delegates, Events and Async Operations


:P
On this page:

Func<T> has been in .NET for a while, but with the arrival of LINQ it’s moved into the limelight as main performer that makes Lambda expressions work. Func<T> is basically a generic delegate that makes it extremely easy to create all sorts of custom delegate signatures without having to explicitly implement the delegates separately.

Events

How often have you lamented the fact that you have to create a custom delegate for an event that needs to fire a method that uses non-typical event arguments? Traditionally you had to create the method and also create a delegate that matched the signature which is a bit verbose at best. Typical event setup code looks something like this:

public event delInvoiceCalculation CalculateTax;
public delegate decimal delInvoiceCalculation(wws_Invoice invoice);
       
public virtual decimal OnCalculateTax(wws_Invoice invoice)
{
    var calcTax = CalculateTax;
    if (calcTax != null)   
        return calcTax(invoice);

    return invoice.Tax;
}

You have to declare a separate delegate and provide the appropriate signature to match the event function that should be called.

Using Func<T> this code can be made a bit cleaner by removing the extra delegate. Here’s another implementation for a similar method using the same signature but using Func<T> or more specifically in this example, Func<T,TResult>

public event Func<wws_Invoice,decimal> CalculateHandling;
public virtual decimal OnCalculateHandling(wws_Invoice invoice)
{
    // TODO: provide logic here
    var calcHandling = CalculateHandling;
    if (calcHandling != null)
        return calcHandling(invoice);

    return Entity.Handling;
}

Func<T> simplifies the event signature a bit by removing the explicit delegate declaration and instead using the generic Func<T,TResult> implementation that allows you to create a custom delegate signature directly on the event. Not only does it save a little bit of code typing, but I also find this easier to see what’s going because it is more explicit in a single statement compared the first snippet where delegate and event declaration are separate (and often completely separated physically because the delegate is reused by multiple events).

Func<T> is a generic function signature/delegate and it works by implementing a delegate by way of its generic parameters. The last generic parameter provided is always the type of the return value (decimal above). Any preceeding generic parameters (up to 4 in Func<T>’s overloads) become the types of input parameters. In this case my signature is for Func<T,TResult> where T is my invoice entity and TResult is bool.

In this respect:

Func<wws_Invoice,decimal>

is equivalent to:

public delegate decimal delInvoiceCalculation(wws_Invoice invoice);

except it doesn’t have to be explicitly declared.

Func<T> in LINQ

Delegates are generally easy to understand but it’s one of those features we don’t use all that often and so it’s easy to forget how they work and what we need them for. Well we know LINQ is full of them – most LINQ operators like .Where() and OrderBy() and Select() to name a few all rely on Func<T> signatures for Lambda expressions. Between Func<T> delegate signatures and lamda expressions statements like this:

Context.wws_Items.Where( itm => itm.Sku == sku );

become possible and quite readable once you get over the initial weirdness of the => operator. What you’re looking at in the Where clause is actually an implemenation of Func<T,bool>:

.FuncTWhere

The input parameter is the the enumerable type (wws_Item from the List<wws_Item> and the return value is bool. The return value is inferred by the compiler and so only the input parameter is used (itm =>) in the lambda expression’s left side. Func<T> is a key feature to make LINQ workable using terse code.

Note that if you use LINQ to SQL or LINQ to Entities Func<T> based parameters to any LINQ commands require an Expression wrapper that wraps the Func<T> expression. This is because these tools delay executing the expressions until a later point in time when the expressions are parsed into some other format (SQL command, Entity SQL or whatever the expression engine uses).

This actually tripped me up yesterday and was what got me on to writing up this content. In my business layer I have basic CRUD operations including the ability to load entities without running a full LINQ command. There’s a base implementation that takes a LINQ expression as a parameter that is passed to a LINQ .Where() method that executes the actual query. At first I passed a Func<T> argument but I quickly found out that this doesn’t actually work – the result from the LINQ to SQL query always returned null. The reason: It’s not an expression that was passed but just a predicate.

I had to make sure the method was declared correctly using an Expression and the correct code that works looks like this:

protected virtual TEntity LoadBase(Expression<Func<TEntity, bool>> whereClauseLambda)
{
    SetError();

    try
    {
        TContext context = Context;

        // If disconnected we'll create a new context
        if (Options.TrackingMode == TrackingMode.Disconnected)
            context = CreateContext();

        Entity = Context.GetTable<TEntity>().Where(whereClauseLambda).SingleOrDefault();

        if (Entity != null)
            OnLoaded(Entity);                

        return Entity;
    }
    catch (InvalidOperationException)
    {
        // Handles errors where an invalid Id was passed, but SQL is valid
        SetError("Couldn't load entity - invalid key provided.");
        Entity = null;
        return null;
    }
    catch (Exception ex)
    {
        // handles any other sql errors                
        Entity = null;
        SetError(ex);
    }

    return null;
}

This makes it super easy to create custom load methods that all use the common LoadBase method and so inherit its behavior. in most cases it becomes as trivial as this:

/// <summary>
/// Loads an individual item by sku
/// </summary>
/// <param name="sku"></param>
/// <returns></returns>
public wws_Item LoadBySku(string sku)
{
    return this.LoadBase(itm => itm.Sku == sku);
}

which is pretty nice and consistent.

Easy Async

Here’s another useful example of how Func<T> can make life a lot easier. For example, kicking off an async delegate with Func<T> becomes a single line operation which makes it a snap to turn just about any operation into an async operation like this async update routine:

public void LogSnippetViewAsync(string snippetId, string ipAddress, string userAgent)
{
    Func<string, string, string, bool> del = this.LogSnippetView;
    del.BeginInvoke(snippetId, ipAddress, userAgent, null, null);
}

public bool LogSnippetView(string snippetId, string ipAddress, string userAgent)
{
    if (string.IsNullOrEmpty(userAgent))
        return false;

    userAgent = userAgent.ToLower();

    if (!(userAgent.Contains("mozilla") || !userAgent.StartsWith("safari") ||
        !userAgent.StartsWith("blackberry") || !userAgent.StartsWith("t-mobile") ||
        !userAgent.StartsWith("htc") || !userAgent.StartsWith("opera")))
        return false;

    this.Context.LogSnippetClick(snippetId, ipAddress); // stored proc

    return true;
}

Here’s Func<T1,T2,T3,TResult> is used to specify 3 parameters (3 strings) and a return value of bool. del is the Delegate declaration and we’re pointing it at the LogSnippetView method to execute. Then BeginInvoke is called to asynchronously launch the method so it runs in the background on a thread pool thread.

Again, using Func<T> avoids having to explicitly declare a delegate separately and instead you can directly declare the delegate signature via Func<T> inline which is easier to read and understand – at least to me.

Sometimes it’s the little things that make life easier and Func<T> is one of those.

Posted in CSharp  LINQ  

The Voices of Reason


 

Svish
October 05, 2009

# re: Easy Async

Say you, after the del.BeginInvoke( ... ) call, continued with some other stuff and then at the end wanted the result of that method you invoked. How would you do that?

Rick Strahl
October 05, 2009

# re: Fun with Func&lt;T,TResult&gt; Delegates, Events and Async Operations

@Svish - it's standard Async behavior, so you'd have either store the result on some shared value (a static value, a common class passed in as a parameter), or you capture the IAsyncResult and then use that to retrieve the result:

void RunDelegate() 
{
  IAsyncResult ar = del.BeginInvoke(snippetId, ipAddress, userAgent, null, null);

  // … some other lengthy processing

  bool result = del.EndInvoke(ar);  // retrieve result/wait for completion 
}


where result is the result value of the method whatever it may be (bool here).The trick is that you have to hang on to the IAsyncResult somehow, so if it's not a single method that the code executes in you need to store it as a class var or somewhere else with some persistence.

Ben Taylor
October 06, 2009

# re: Fun with Func&lt;T,TResult&gt; Delegates, Events and Async Operations

Nice use of Funq Rick! It is fast becoming my favourite .NET type.

One small niggle. I don't think your event hookup code is thread-safe, so it's not really typical. CalculateHandling should be assigned to a temp variable before checking for null otherwise you can get a race condition as described here http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx.

To avoid such tedious, nit-picking code, I create an extension method called Raise which handles all this for you so you can just write CalculateTax.Raise(entity). Here is an example implementation http://blogs.microsoft.co.il/blogs/shayf/archive/2009/05/25/a-handy-extension-method-raise-events-safely.aspx.

Svish
October 06, 2009

# re: Fun with Func&lt;T,TResult&gt; Delegates, Events and Async Operations

@Ben Taylor: I prefer to just initialize the events with an empty handler, and then just call it without null-checking I find it to work much easier.

public event EventHandler<EventArgs> SomeEvent = (s, e) => { };

SomeEvent(this, EventArgs.Empty);

Ben Taylor
October 06, 2009

# re: Fun with Func&lt;T,TResult&gt; Delegates, Events and Async Operations

@svish Yes, that is also a handy technique. However, I don't like to use it as you have to look at the event declaration to know if such a call is safe. When working on an existing code base or in a team this can leave you feeling unsure of the call. I like the Raise extension method is explicit and inline.

Svish
October 06, 2009

# re: Fun with Func&lt;T,TResult&gt; Delegates, Events and Async Operations

True I guess, but if your class is so big that you have trouble seeing that, then I would say it is time for a refactoring. And also, events should usually be raised using an OnSomeEvent method for example. If they are to be raised by descendants that is...

A
October 06, 2009

# re: Fun with Func&lt;T,TResult&gt; Delegates, Events and Async Operations

@Svish, Eric Lippert disagrees with you, and I agree with him. (sorry I tried to find his comment on Stack Overflow, but it's there somewhere)

I hate to be pedantic, and I'm afraid I'm on the losing side of the lazy, but here goes....

It's wasteful of memory.
It wastes time dispatching to a handler that does nothing.
The class can still set the event to null, meaning you can still get a null reference exception.
You still have a race condition.

It's a cute trick for presentation code, nothing more. The world is a happier place if you just follow the recommended practice of:

public event EventHandler<EventArgs> SomeEvent;

// if sealed class, obviously not virtual .
protected virtual void OnSomeEvent(object sender, EventArgs args)
{
  EventHandler<EventArgs> handler = SomeEvent;
  if( handler != null )
  {
     handler(sender,args);
  }
}


Any derived classes can then override the behavior as necessary without requiring access to the event itself.

If the class is sealed it's not a big change.

Rick Strahl
October 06, 2009

# re: Fun with Func&lt;T,TResult&gt; Delegates, Events and Async Operations

@Sven - I've updated the code in the post to include the local assignment. Although from reading Eric's post I'm still not quite clear whether this solves the problem completely I can see that it makes it a heck of a lot less likely to fail (and it's a fairly unlikely fail to begin with IMHO).

Interesting discussion - something I hadn't given a ton of thought to before.

Ben Taylor
October 07, 2009

# re: Fun with Func&lt;T,TResult&gt; Delegates, Events and Async Operations

@Rick Previously, your code could have resulted in a NullReferenceException due to the race condition. Now, your event firing code is thread-safe and that exception will not occur. What Eric points out, is that there is also a secondary race issue. That is, the code that handles the the CalculateTax event could actually be called AFTER it had unsubscribed from the event (using the -= syntax). Obviously, this could cause unexpected behaviour in your system. To solve this you have to write code in the event handler to deal with the scenario of being called after you've asked NOT to be called.

Nordine Ben Bachir
October 08, 2009

# re: Fun with Func&lt;T,TResult&gt; Delegates, Events and Async Operations

The only annoying thing is that events declared as Func or Action cannot have multiple subscribers. Or am I wrong?

--Nordine

JP
October 09, 2009

# re: Fun with Func&lt;T,TResult&gt; Delegates, Events and Async Operations

One nice side effect of getting accustomed to Expressions is that they can be serialized. This obviously opens up a whole new set of possibilities. For instance you can now do repositories with simple API's using WCF. Check out http://code.msdn.microsoft.com/exprserialization for more info. IMHO its an extremely under-hyped library.

Chuck
October 21, 2010

# re: Fun with Func&lt;T,TResult&gt; Delegates, Events and Async Operations

Rick I really like your posts, and return to the one on url's in asp.net a lot.

I thought I'd share an extension method I'd been thinking of writing while reading your post. I found myself writing if(asscending) return orderby... else return orderbydescending, over and over in a switch, so made this instead.
public static IEnumerable<T> OrderBy<T, TKey>(this IEnumerable<T> source, Func<T, TKey> f, bool asscending)
{
    if (asscending) return source.OrderBy(f);
    return source.OrderByDescending(f);
}

One question, what does doing Expression<Func<>> do for you? I don't get that.

Also, you've probably already caught this in your code, but you did TContext context = Context;, then an if() context = ... then you don't use the variable context but your property Context in your call.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024