Thinking outside the box

SteelePrice.Net

My Links

Twitter Updates


Get Microsoft Silverlight
follow me

Article Categories

Archives

Post Categories

Image Galleries

Dot Net

General

Linux

OneNote

Windows

TechED Bloggers
Visual Basic Bloggers (OPML)

September 2006 Entries

Anonymous Delegates (Methods) and Visual Basic (VB)

What is an Anonymous Delegate?

I have recently been converting these and talking about them quite alot.

This is a technique not currently implemented in VB, but is used in C# (and other languages) to write some inline code in which I do not want to create classes and handlers to perform some simple operation. Typically this is used in Generics when iterating over a collection, or to execute some specific functionality when an event occurs.

These are similar to "Closures" in other languages see:

http://en.wikipedia.org/wiki/Closure_(computer_science)
http://www.martinfowler.com/bliki/Closure.html

OK, so if these are NOT supported in VB, then why as a VB Developer should I care? Specifically, as more and more C# examples using these are posted, there will be an occassion where you really want to use the posted technique and don't quite get how to transalate it into VB.

There are several way's to work with itteration, so in this sample, I will focus on using delegates for Asynchronous Callbacks such as adding an event listener that performs a set of operations when an event fires. This is a little more difficult to grasp than simple iteration and it also happens to be extremely useful in the event based programming model.

What does one look like?

It can be as simple as adding a handler to an event, in C#:

button1.Click += delegate {MessageBox.Show("Hello");};

So that is the simplified code, lets break it down first in VB terms:

button1.click is an event (obviously...)
+= will add what is inside the delegate{}; block as a new handler, if one (or more) already exists, it will perform this one in the order in which added. In C# the handler is created automatically by the compiler (thus the anonymous part, since we didn't have to give the function a name...) so it is not done manually as we will need to in VB.

A Click event is oviously radically simplified for realizing the power and usefullness of this coding model. What is cool about an Anonymous Delegate is that you can pass local variables to a set of code that you could not otherwise do in VB. Consider a more real-world example, since I have also been working with System.Transactions:

 

transaction.TransactionCompleted += delegate
                                    {
                                       lock(this)
                                       {
                                          m_PendingTransactions.Remove(pair);
                                       }
                                       lock(manualEvent)
                                       {
                                          if(manualEvent.SafeWaitHandle.IsClosed == false)
                                          {
                                             manualEvent.Set();
                                          }
                                       }
                                    };

This code is admitedlly daunting because it uses 3 uncommon things in VB. First, we are assigning code to a multicast event, secondly we have the use of an Anonymus Delegate, then thirdly we have some Thread Safty being applied.

So what do I do in VB when I see some sample code in C# that contains things like this? One option you could apply is to fire up .Net Reflector and have a look at what is going on. so, lets do that:

 

If (handler1 Is Nothing) Then
    handler1 = New TransactionCompletedEventHandler(AddressOf class1.<Lock>b__0)
End If
AddHandler transaction.TransactionCompleted, handler1

This tends to still be quite cryptic since it uses the compiler created names to describe the functions. It also doesn't help when you are looking at a block of code and don't want to copy/create project/compile it.

In reviewing this code... what is handler1?, what is class1? and what the heck is this class1.<Lock>b__0)

Now it starts to get a bit hairy, especially if you don't know C# very well or what the compiler is doing behind the scenes.

Let me explain what happened here when we look at the Code. Since we do not have Anonymous Delegates in VB, we have to make class1 to hold the State information and the Method (Sub) we want to run, the compiler in C# decided that should be class1 and class1.<Lock>b__0) Next we need to pass in all the state information that the Anonymous Delegate was allowed to just use, now are you starting to see why these things are cool?

We have to look a little bit higher in the Code to see where that all happens:

 

Dim handler1 As TransactionCompletedEventHandler = Nothing
Dim class1 As New <>c__DisplayClass2
class1.<>4__this = Me
class1.manualEvent = New ManualResetEvent(False)
class1.pair = New KeyValuePair(Of Transaction, ManualResetEvent)(transaction, class1.manualEvent)

There is still a bunch of cryptic stuff in here...

handler1
<>c__DisplayClass2
class1.<>4__this

These also got created by the compiler and just generated the names, so they aren't especially helpful.

So, when you see this: There are 5 things you need to do to implement this code in VB:

  1. Make a Private NotInheritable Class with an empty constructor
  2. Create Fields to hold each variable
  3. Create a Sub that matches the Signature you need to Delegate
  4. Perfom the desired functionality inside this Sub, operating on the Class&squot;s Fields
  5. Use AddHandler to point to the Class's Sub and run it at the appropriate time

Let have a look at what the Final cleaned up Code in VB looks like and then go through it.

Private NotInheritable Class TransactionState
    Public tLock As TransactionalLock
    Public manualEvent As ManualResetEvent
    Public pair As KeyValuePair(Of Transaction, ManualResetEvent)

    Public Sub New()
    End Sub

    Public Sub RemoveSelf(ByVal sender As Object, ByVal e As TransactionEventArgs)
        With Me
            SyncLock .tLock
                .tLock.m_PendingTransactions.Remove(DirectCast(.pair, KeyValuePair(Of Transaction, ManualResetEvent)))
            End SyncLock
            SyncLock .manualEvent
                If Not .manualEvent.SafeWaitHandle.IsClosed Then
                    .manualEvent.Set()
                End If
            End SyncLock
        End With
    End Sub
End Class

Private Overloads Sub Lock(ByVal transaction As Transaction)
    If (OwningTransaction = Nothing) Then
        ''' Other stuff
    Else 
        If (OwningTransaction = transaction) Then
            Return
        Else 'Need to lock when different
            Dim manualEvent As New ManualResetEvent(False)
            Dim pair As New KeyValuePair(Of Transaction, ManualResetEvent)
            Dim tHandler As TransactionCompletedEventHandler
            Dim TranState As New TransactionState

            With TranState
                .tLock = Me
                .manualEvent = New ManualResetEvent(False)
                .pair = New KeyValuePair(Of Transaction, ManualResetEvent)(transaction, .manualEvent)
            End With

            ''' Other stuff
            If (transaction IsNot Nothing) Then
                If (tHandler Is Nothing) Then
                    tHandler = New TransactionCompletedEventHandler(AddressOf TranState.RemoveSelf)
                End If
                AddHandler transaction.TransactionCompleted, tHandler
            End If
            ''' other stuff
        End If
    End If
End Sub

First for the renaming of what we saw in Reflector:

class1 = TranState
handler1 = tHandler
<>c__DisplayClass2 = TransactionState
.<>4__this = tLock
and
.<Lock>b__0= .RemoveSelf

Now let see what we had to do:

First we have to create a Named Class that does what the delegate does, this is Class TransactionState. Next inside that class, we need to create fields to hold all the state information for the state of the variables when we instantiate the Class.

Armed with the Class we can now instantiate the Class, Populate the Fields with our Variables then Add an new Handler that listens for the TransactionCompleted Event and runs the Sub in the Class when it fires.

As you can see just from the amount of code, having Anonymous Delegates in VB would make this drastically simpler to implement, however it IS indeed possible to convert this code to VB with a little work and the understanding of what is going on. I do these types of Classes already so it was not a huge surprise to see the functionality, but what really surprised me was how much easier it could be when we get Anonymous Delegates to shortcut the whole idea.

There are many of us fighting hard to have Anonymous Delegates in VB9, but it unfortunately may be too late and we might have to wait until VB10, that would be extremely dissapointing since we are going to get something called a Lambda Expression in VB9 that is fairly close (part of LINQ, a one line quick expression) but certainly not as powerful as a full inline function.

If C# has them, the compiler knows how to create them, so it should not be a huge task to actually include it, but I am not on the VB Design team so I really don't know what it would take inside the compiler and parsers to provide it to VB. Hopefully we will see them soon as a natural part of the evolving VB.NET Language and when we need to convert some C# code into something more useful for our VB Projects, we will not have to be so verbose.

posted @ Thursday, September 28, 2006 4:08 PM | Feedback (1)

Microsoft Open Specification Promise

Microsoft irrevocably promises not to assert any Microsoft Necessary Claims against you...

It's nice to know that the patent police aren't going to knock down my door when I make my music library use a web service... DRM is another story...  I'd like to see more promises like this from more companies and make public standards completely public.

While I am all for protecting one's “intellectual property” we also need to share a set of standards in a very open way.  If there are no standards to follow, then we all suffer from NIH syndrome, innovation is stifled and software applications cannot talk to each other.

No one needs to sign anything or even reference anything.

This is good to know... I don't need to worry about referencing some arcane GPL style license or conform to some esoteric command the gods of standards think I should be forced into complying with.

Share great ideas and the world benefits...  We really need more of this from more companies and for more of them to work with each other to make a set of LOOSE rules that we can all use to make interoperative services and not have to worry about paying 5 different companies a fraction of a penny for every transaction.  Capitalism is great, but sometimes we just need to draw some lines on the playground and let people make up their own games.

posted @ Wednesday, September 13, 2006 10:27 AM | Feedback (0)

Speaking 9/20 in Tucson (updated)

I will be speaking in Tuscon, AZ to the Tuscon .Net User Group on Wednesday, September 20th, at 6:30 p.m

The topic will be System.Transactions:

As .NET developers we must often choose between two transactional programming models: explicit local transaction management or declarative use of the DTC via Enterprise Services. Alternatively, the .NET Framework 2.0 introduced a new transactional programming model available in the System.Transactions namespace. In this presentation, learn the practical techniques behind this new model. Understand how System.Transactions is not just for Databases and the performance benefits of explicit transaction management. Find out how to enable distribution across the Web without major application code changes. Also covered are other interesting features such as concurrency management, cloning and state recovery with volatile resource managers.

VB Code samples and slides for this presentation will be posted here shortly.

posted @ Friday, September 08, 2006 3:25 PM | Feedback (1)

Blogroll Me!

Blog Search Engine

Copyright © 2003-2004 H. Steele Price, IV -
All opinions are my own, not necessarily those of my employer, your mother, or any government agency.