Func
, Action, Predicate
In VB.NET, we sometimes need to create function objects to pass to other methods (like List
methods). We can create Func
, Action and Predicate
objects with lambdas.
We use the Function or Sub
keywords to create these function objects. Funcs and Predicates return a value, so use the Function keyword.
Sub
keyword to specify an Action type.Func
exampleLet us begin with the Func
type. When we create a Func
, we specify its argument types (if any) and then its return type. Only one return type can be used.
Module Module1 Sub Main() ' Return an Integer with no arguments. Dim test As Func(Of Integer) = Function() 10 Dim result = test.Invoke() Console.WriteLine($"TEST RESULT: {result}") ' Return an Integer with a String argument. ' ... Returns the string length multiplied by 2. Dim test2 As Func(Of String, Integer) = Function(x) x.Length * 2 Dim result2 = test2.Invoke("bird") Console.WriteLine($"TEST2 RESULT: {result2}") End Sub End ModuleTEST RESULT: 10 TEST2 RESULT: 8
Action is the same as a Func
, but it returns no value—it is like a Subroutine instead of a Function (in VB.NET terms). Here we create an action that receives 2 integers.
Sub
. It returns no value. Instead it just calls Console.WriteLine
.Module Module1 Sub Main() ' Use Sub to create an action. Dim test As Action(Of Integer, Integer) = Sub(x, y) Console.WriteLine("X is {0}, Y is {1}", x, y) ' Call the Action 3 times. test.Invoke(10, 20) test.Invoke(20, 30) test.Invoke(30, -1) End Sub End ModuleX is 10, Y is 20 X is 20, Y is 30 X is 30, Y is -1
Predicate
exampleA Predicate
is a function object that receives arguments, and always returns a Boolean
. It tells us whether something is true or false.
Module Module1 Sub Main() ' This Predicate receives an Integer, and returns a Boolean. ' ... It tells us if an Integer is positive. Dim isPositive As Predicate(Of Integer) = Function(x) x >= 0 If isPositive.Invoke(10) Then Console.WriteLine("NUMBER IS POSITIVE") End If ' This Predicate receives a String. ' ... It returns true if the string is short (less than 10 chars). Dim isShortString As Predicate(Of String) = Function(value) value.Length <= 9 If isShortString.Invoke("this is a long string") Then ' This is not reached. Console.WriteLine("NOT REACHED") End If End Sub End ModuleNUMBER IS POSITIVE
We usually want to pass things like a Predicate
to another Function. Consider the FirstOrDefault
Function from LINQ. It can accept a Predicate
argument.
Predicate
that returns True when a String
begins with the letter F.string
that begins with the letter F, "frog," is returned by the FirstOrDefault
Function. The Predicate
worked.Module Module1 Sub Main() Dim values() As String = {"bird", "frog", "dog", "cat"} ' Use Predicate to find first item starting with lowercase F. Dim firstLetterF = values.FirstOrDefault(Function(x) x.StartsWith("f")) ' Result. Console.WriteLine("FIRST ITEM STARTING WITH F: {0}", firstLetterF) End Sub End ModuleFIRST ITEM STARTING WITH F: frog
Usually when we need a Func
, Action or Predicate
, it is as an argument to another method. Many methods in LINQ (like FirstOrDefault
) can optionally accept a function object.
Often we encounter a Function that requires a Func
, Action or Predicate
argument. We can create these with Lambda syntax—the arguments and return value must be specified.