Passing parameters to delegates in VB.NET

In C# we have anonymous methods. You can read about them and how they are implemented in this post on Raymond Chens blog:

http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx

One of the features of anonymous methods is they allow you to use variables that would normally be out of scope. Raymond explains that this works by generating a class under the hood, populating it with the variables and then passing the method. Here is an example of what C# can do:

public void Main() 
{
    var developers = new List<string>(new []  { "Woody Allen", "Bill Gates" } );

    var greatDeveloperFirstName = "Bill";

    var greatDevelopers = developers.FindAll(
        delegate (string developerName) {
            // Note that I am using a variable that would be "out of scope" if 
            // this wasn't an anonymous method:
            return developerName.StartsWith(greatDeveloperFirstName);
        });
}

In VB.NET, since you can't do anonymous methods, it also makes it hard to pass arguments to methods that expect a Predicate<T> (such as List<T>.FindAll()).

Here's a VB.NET class that you can reuse to "wrap" a Predicate<T> in order to pass arguments to it.

Public Delegate Function PredicateWrapperDelegate(Of T, A) _
    (ByVal item As T, ByVal argument As A) As Boolean

Public Class PredicateWrapper(Of T, A)
    Private _argument As A
    Private _wrapperDelegate As PredicateWrapperDelegate(Of T, A)

    Public Sub New(ByVal argument As A, _ 
        ByVal wrapperDelegate As PredicateWrapperDelegate(Of T, A))

        _argument = argument
        _wrapperDelegate = wrapperDelegate
    End Sub

    Private Function InnerPredicate(ByVal item As T) As Boolean
        Return _wrapperDelegate(item, _argument)
    End Function

    Public Shared Widening Operator CType( _
        ByVal wrapper As PredicateWrapper(Of T, A)) _
        As Predicate(Of T)

        Return New Predicate(Of T)(AddressOf wrapper.InnerPredicate)
    End Operator

End Class

To use this class in your VB.NET code:

Sub Main()

    Dim developers As New List(Of String)
    developers.Add("Paul Stovell")
    developers.Add("Bill Gates")

    Dim greatDeveloperFirstName as string = "Paul" 

    Dim greatDevelopers As List(Of String) = developers.FindAll(_ 
        New PredicateWrapper(Of String, String)(  _
            greatDeveloperFirstName, _
            AddressOf IsGreatDeveloper))

    For Each greatDeveloper As String In greatDevelopers
        Console.WriteLine(greatDeveloper)
    Next

    Console.ReadKey()

End Sub

Note that you can now pass arguments to your "FindAll" predicate :)

Function IsGreatDeveloper(ByVal item As String, ByVal argument As String) As Boolean        
    Return item.StartsWith(argument)
End Function
A picture of me

Welcome, my name is Paul Stovell. I live in Brisbane and work on Octopus Deploy, an automated deployment tool for .NET applications.

Prior to founding Octopus Deploy, I worked for an investment bank in London building WPF applications, and before that I worked for Readify, an Australian .NET consulting firm. I also worked on a number of open source projects and was an active user group presenter. I was a Microsoft MVP for WPF from 2006 to 2013.