I have started working through The Art of Unit Testing by Roy Osherove and came upon this test that took me a while to understand:
[Test] public void IsValidFileName_EmptyFileName_Throws() { var ex = Assert.Catch<Exception>(() => la.IsValidLogFileName("")); StringAssert.Contains("filename has to be provided", ex.Message); }
I was really confused about what was happening on line 4. Looking at the NUnit documentation, I saw that this is format for the Assert.Catch
method:
T Assert.Catch<T>(TestDelegate code);
The method is going to return an exception, but it needs to be passed a TestDelegate
first. We can see the syntax for a TestDelegate
here:
public delegate Void TestDelegate ()
This seems strange because according to the code, Assert.Catch
is being passed a lambda expression:
() => la.IsValidLogFileName("")
Well it turns out that Lambda expressions are a simpler syntax for anonymous delegates and can be used everywhere an anonymous delegate can be used. The Microsoft docs even say as much:
a lambda expression is just another way of specifying a delegate
The question is then, “what is a delegate?” From my research, a delegate is used in C# when you want to pass a function itself as a parameter. You often see people refer to a delegate as “a pointer to a function.” The syntax for creating a delegate is as follows:
<access modifier> delegate <return type> <delegate_name>(<parameters>)
And here is some example code using a delegate:
class Program { public delegate void Print(int value); static void Main(string[] args) { Print printDel = PrintNumber; // or you can do this: // Print printDel = new Print(PrintNumber); printDel(100000); printDel(200); printDel = PrintMoney; printDel(10000); printDel(200); } public static void PrintNumber(int num) { Console.WriteLine("Number: {0,-12:N0}",num); } public static void PrintMoney(int money) { Console.WriteLine("Money: {0:C}", money); } }
And here is the output:
Number: 10,000 Number: 200 Money: $ 10,000.00 Money: $ 200.00
Let’s understand what’s happening here.
- We are declaring a delegate called
Print
that takes an integer as an argument. We create a new instance of this delegate can call itprintDel
. - We point
printDel
at thePrintNumber
function. - We call our delegate twice, passing it in two different values. It formats the numbers appropriately with commas as specified in the
PrintNumber
method. - We then point
printDel
at thePrintMoney
function. - We call our delegate two more times and this time it formats the numbers for currency as described in the
PrintMoney
function.
So, in summary, if we use a delegate, we’re passing a pointer to chunk of code, whereas if we use a lambda, we’re passing the code directly (and anonymously). Lambdas are more convenient in this case because we don’t have to declare them or even give them a name.