Deep C# - Anonymous Methods, Lambdas And Closures
Monday, 19 September 2016
Article Index
Deep C# - Anonymous Methods, Lambdas And Closures
From Anonymous Methods to Lamdas
Expressions Lambda to Expression Trees
Closure
Two Patterns for Closure

Using Closure 1 - More parameters

Clearly closures are fun but what use are they?

The answer is that they provide a context for a function which can be used to provide it with additional information without the need to use additional parameters.

Why wouldn’t you create some additional parameters?

Most likely because the signature of the function you are trying to use isn’t under your control.

Banner

For example consider the EnumWindows API call which needs a callback function that is called for each window that it enumerates. The API call is:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
      static extern bool EnumWindows(
          EnumWindowsProc lpEnumFunc,
          ref IntPtr lParam);

and the callback delegate is:

public delegate bool EnumWindowsProc(
          IntPtr hWnd,
          ref IntPtr lParam);

The problem with using the callback delegate is that it only has the two parameters - the handle of the current window and a pointer supplied in the call to the EnumWindows function.

It is this pointer that is used to communicate between the callback function and the program needing the enumeration.

Closure, however, makes communication much easier.

If you need a function to find a particular dialog box specified by its Owner and its Caption string then you could write a function something like:

public IntPtr getDialog(IntPtr Owner, String Caption)
{

Clearly we need to pass the Owner and Caption to the callback delegate so that it can compare each of the enumerated windows to the target. The most natural way to do this is to provide these extra pieces of information to the callback via extra parameters but to work as a callback it can only have the parameters defined by the API.

The simplest solution is to define the callback delegate in the usual way but use the fact that the Owner  and Caption parameters are in scope and so are captured by an anonymous function:

EnumWindowsProc enumProc =
  delegate(IntPtr handle, ref IntPtr pointer)
{

First we get the window text and compare it to Caption, which we can only access here thanks to closure:

int length = GetWindowTextLength(handle);
StringBuilder wTitle = new StringBuilder(length + 1);
GetWindowText(handle, wTitle, wTitle.Capacity);
if (wTitle.ToString() == Caption)
{

If they match we check that the class name is correct for a dialog box and then check that Owner, which is once again only accessible at this point because of closure, is the correct window:

  int max = 100;
  StringBuilder classname = new StringBuilder(max);
  GetClassName(handle, classname, max);
  if (classname.ToString() == "#32770")
  {
    IntPtr Parent = GetParent(handle);
    if (Parent == Owner)
    {
     pointer = handle;
     return false;
    }
  }
 }
 return true;
};

This completes the anonymous callback delegate; now we can call EnumWindows:

IntPtr DlgHwnd = IntPtr.Zero;
EnumWindows(enumProc, ref DlgHwnd);
return DlgHwnd;
}

To follow what is going on here you need to keep in mind that the callback is actually run by the API  via the call

enumProc(handle,pointer);

which passes in the handle to the window and a pointer to soon additional data. The Owner and Caption variables are used within the callback courtesy of closure.

Notice that the pointer in the callback delegate is used to return the handle of the dialog box that we have found but this too could have been achieved using closure.

Without any use of closure we would have had to pack the Owner and Caption into a data structure and passed this to the callback. Closure makes things much simpler in this case.

Using Closure 2 - Event pattern

There is one very important situation where closure simplifies things - although not everyone agrees that it is a good idea. In an event oriented environment the linear flow of actions is often made unclear by the need to pause processing until an event occurs. Situations like this occur all the time but to make the explanation easier to follow let's try to remain as general as possible 

Suppose you are writing some code that works with some resources and you get to the point where you need to load a new resource and this is a time consuming action then there are two approaches blocking synchronous and non-blocking asynchronous. Blocking synchronous simply causes the thread doing the work to pause until the resource is loaded:

work with resources
request new resource
wait(until resource loaded)
continue with processing

This has the advantage of simplicity and you can clearly see what is happening but if the processing thread is also processing events then all event handling stops at the wait. This is a common problem that can be partly alleviated by use of constructs such as DoEvents which sends the thread off to process events while waiting:

work with resources
request new resource
Do Until (resource loaded)
 DoEvents
Loop
continue with processing

This approach has many problems - the biggest being reentrancy, i.e. what if an event that occurs as the result of DoEvents restarts the entire method over again.

The second approach, non-blocking asynchronous, is to use an event to trigger the resumption of the processing when the resource has loaded. For example,

work with resources
setup "resource loaded" event handler
request new resource
end method

When the method ends the thread can continue to process events and when the resource is loaded the assigned event handler is invoked and processing continues,

The problem with this is that the event handler has to be written else where and its self contained and doesn't share access to any of the resources of the original processing method. That is the logic of the program says:

do actions A
load  new resource
do actions B
end AB

and A and B are linked in the sense that B might well need access to variables that were created as part of A but the need not to block the thread waiting for the resource load mean this has to be written as:

do actions A
set B to be onload event handler
load new resource
end A

onload
Do B
end B

Not only is the flow of control confused by this break but B doesn't have access to the variables etc in the scope of A.

At this point you should be thinking - closure.

If the event handler is defined as an anonymous method in the scope of A then when it runs, whenever that might be it has access to the original environment provided by A. That is:

do actions A
set B to be onload event handler
load new resource

onload anonymous method
Do B
end B
end A

Now not only is it clear that the flow of control is do A then do B but B has access all of the variables defined in A and can continue the processing as if it hadn't had to wait for an event.

If you would like to see a practical example of this in action then see Loading Bitmaps: DoEvents and the closure pattern.

The use of closure to make non-blocking asynchronous coding look more like blocking synchronous coding is one of the big advantages of using a closure - but don't over use it!

In modern C# a better way of handling events and asynchronous code is to use async and await.

csharp

Deep C#

 front

 Chapter List

  1. Value And Reference
  2. Dynamic C#
  3. Passing Parameters
  4. Inheritance 
  5. Casting – the escape from strong typing
  6. Controlling Inheritance
  7. Delegates
  8. Multicast delegates and events
  9. Anonymous Methods, Lambdas And Closures
  10. Take Exception To Everything
  11. What's The Matter With Pointers?
  12. Generics
  13. Structs
  14. The LINQ Principle
  15. XML in C#
  16. Linq and XML
  17. Regular Expressions in depth
  18. Bit Manipulation
  19. Async, Await and the UI problem ***NEW
  20. The Invoke pattern
  21. The Parallel For
  22. Not so complex numbers in C#
  23. Getting Started With .NET IL
Multicast delegates and events
Tuesday, 25 May 2010
Article Index
Multicast delegates and events
Events
Generic Events

Multicast delegates are useful in their own right but they also form the basis on which the C# event system is built. We take a close look at how they work and how to use them. For example, did you know you could add and subtract delegates?

square

 



 

Comments




or email your comment to: comments@i-programmer.info

 

<ASIN:0321658701>
<ASIN:1451531168>

<ASIN:0321637003>

<ASIN:0596800959>

<ASIN:047043452X>

<ASIN:0123745144>

 



Last Updated ( Thursday, 22 September 2016 )