Delegates are used “under-the-covers” to implement events (i.e., event handlers are the callback methods). Moreover, anonymous delegates are the basis for lambda expression in .NET. In general, delegates can be used to parameterize functionality that must be dynamically provided at runtime.
What are They?
Delegates are .NET objects that wrap methods allowing them to be effectively passed around within an application at runtime and invoked.

Consider the Filter class in Snippet 1. In this class the Find method iterates through a list of products and uses the delegate filterMethod, passed as a parameter [2], to determine whether a given product should be included in the result list. In other words, the specific method to invoke is NOT known by the code at compile-time. Instead, filterMethod(p)[3] will invoke whatever method has been wrapped by the calling code and passed to Find at runtime.
Any method passed into the Find method must adhere to the signature defined as part of the delegate declaration. In this case, the method must return a Boolean and take a Product as its sole argument. Other languages, such as C, support function pointers. Though equivalent in functionality to delegates, function pointers do not force a signature upon the provided methods allowing the invoking code to pass arguments that were not defined by the provided method. Can you say runtime bug waiting to happen, security threat, etc.?

Snippet 2 provides an example of how the Find method might be used. First, methods ProductFilter01 and ProductFilter02 are defined. Referred to as callback methods, each of these adheres to the delegate signature (i.e., returns a Boolean and takes a single Product instance as a parameter) and may, therefore, be passed to the Find method. To pass in ProductFilter01 we first “wrap” it in a new instance of FilterDelegate and then provide this wrapper as an argument to Find.
.NET 2.0 introduced the concept of delegate inference in which the type of the delegate is inferred from the assignment statement.

As shown above, this reduces the amount of code needed to construct delegate instances and is much more natural from a syntactical perspective. Under-the-covers, the compiler deduces the type of delegate needed and actually constructs code resembling the more traditional approach to delegate creation shown in the snippet [1].
In addition, with .NET 2.0 anonymous delegates a developer need not create an explicit delegate function as shown in Snippet 2. Instead, the developer can define the delegate function on the fly as shown below [1] by using the delegate keyword.

Note that the delegate could have been defined within the call as well.
