Let's say we have a method as below -
public static bool should_be<T>(this T item, Func<T, bool> evaluationWith)
{
return evaluationWith(item);
}
What is this doing? I'll attempt to explain. Firstly it’s worth noting that the method is an extension method which means it extends an already existing class. The method is also a generic method which means it can extend any class, so we could call the method like this on an integer -
int i;
i = 3;
i.should_be(args);
or like this on a string -
string str;
str = "blah blah blah";
str.should_be(args);
The ‘this T item’ text within the signature of the function means that within the function the variable ‘item’ refers to the class being acted upon, so in our first example ‘item’ would refer to the integer 3 and in the second example item it would refer to the string “blah blah blah”. It’s important to remember that even though the ‘item’ parameter is included in the arguments list of the function it is not passed to the function when it is called (hence each of our examples only pass one argument to the should_be function). The function derives the value of the ‘item’ parameter from the object it is being called upon.
The ‘Func<T, bool> evaluationWith’ text within the signature means that the ‘should_be’ function expects another function to be passed as the only argument to the ‘should_be’ function. This can take a while to get your head around, I find it easier to comprehend if I consider the following two function signatures -
public static void should_be<T>(this T item, Func<T, bool> evalueationWith)
public static void should_be<T>(this T item, int evalueationWith)
The second signature looks straightforward and all that has been changed from the first signature is that we are passing in a type of ‘int’ rather than a type of ‘Func<T, bool>’. In .Net the type ‘Func<T, bool>’ refers to a function which takes an argument of type T and returns a Boolean. The ‘should_be’ function defines type T as being the same type as the class that is being extended, so in our first example where we call the should_be function on the integer 3 the ‘should_be’ function expects a function to be passed as an argument that takes a single integer argument and returns a Boolean. The function below would fit the bill perfectly -
bool EqualToThree(int tint) {
return tint == 3;
}
We can now extend our first example to include our newly defined function and get a functional piece of code -
int i;
i = 3;
i.should_be(EqualToThree);
Here’s what’s happening in the guts of the ‘should_be’ function -
- The function equates the variable ‘item’ to the value of the current class, in this case that means that the item variable equals 3
- The function calls the function passed into itself (‘evaluationWith’) using the item variable as the argument to the function, so the function is effectively calling the following code - ‘isIntegerEqualToThree(3)’, the value true is returned.
For the sake of completeness here’s some code that would get our second string example working -
static bool EqualToBlahBlahBlah(string tstring)
{
return tstring == "blah blah blah";
}
string str;
str = "blah blah blah";
Console.WriteLine(str.should_be(EqualToBlahBlahBlah));
Generic Method Definition
Generic methods need to be defined in a certain way in order for them to work, here’s the code contained in the class that defines the ‘should_be’ function -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CustomExtensions
{
public static class CustomExtensions
{
public static bool should_be<T>(this T item, Func<T, bool> evaluationWith)
{
return evaluationWith(item);
}
}
}
Note that the method is defined within a public static class. Finally here’s the code that calls the extension method as part of a simple console application -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ExtensionGenerics
{
using CustomExtensions;
class Program
{
static void Main(string[] args)
{
int i;
i = 3;
Console.WriteLine(i.should_be(EqualToThree));
string str;
str = "blah blah blah";
Console.WriteLine(str.should_be(EqualToBlahBlahBlah));
Console.ReadLine();
}
static bool EqualToThree(int tint)
{
return tint == 3;
}
static bool EqualToBlahBlahBlah(string tstring)
{
return tstring == "blah blah blah";
}
}
}
You can download the full project code
here.