This is actually a smaller topic than anonymous methods, but it'll make the topic of
anonymous methods easier to understand, by keeping the code smaller. Basically,
delegate inference lets you create a delegate instance without the new DelegateType
part wherever the compiler can work out which delegate you mean. Here's an example:

This can be used with events (e.g. button.Click += ClickHandler;) and
anonymous methods. Occasionally you will need to tell the compiler
what kind of delegate you're trying to build, in which case the old syntax is the way to go.

In earlier versions of C#, the signature of the method used to implement a delegate
had to match the delegate signature exactly, including return type. In C# 2.0,
return types can be covariant and parameter types can be contra-variant. Now, these
are big words which basically mean "you're allowed to use any method which is guaranteed
not to muck things up". To be specific:

Return type covariance means that if a delegate is declared to return a base type,
an instance can be created using a method which is declared to return a type derived from it.

Parameter type contra-variance means that if a delegate parameter is declared to be
a derived type, an instance can be created using a method which has a base type for that
parameter.

The reason this works is that any caller of the delegate must provide arguments matching
the delegate's signature (and those arguments will always be compatible with base types of the
parameters), and the implementation just has to guarantee that it will return something which
can be treated as a value of the declared return type of the delegate.

Any string argument which could be passed into the delegate is fine to be treated
as an object reference by SomeMethod, and any UTF8Encoding
returned by SomeMethod can be treated as an Encoding reference by the
caller.

Delegates are a wonderful idea. They make eventing models simpler, and get away
from a lot of single method interfaces (or worse, multiple method interfaces with adapters
which do nothing until they're overridden) which afflict Java. Java came up with a way to
make it slightly less painful to override a single method than it would be otherwise:
anonymous inner classes. These allow you to derive from a class or implement an interface
"inline" in the middle of a method. They allow you to use local variables from the method
you're running in (with restrictions) and even private variables and methods from the class
you're running in. As you're deriving from one class and have implicit access to an instance
of another, it's almost as if you get multiple inheritance. Almost. Unfortunately, they
look pretty ugly. Here's an example:

This creates an implementation of the SomeActionable interface inline - it just prints out the
first command line parameter specified. It's often better than having a whole class just for the sake
of doing something (especially if you have lots of different implementations, each of which is really
just a line of code), but it's ugly to look at and gets worse if you need to distinguish between
accessing the class you're actually deriving from and the class you're declaring the anonymous inner class in.

Now, back to C#. In versions prior to 2.0, you couldn't create a delegate instance unless you had a normal method
which had the code you wanted to run. When the delegate only needs to do one thing (e.g. pass on the call to
another component, with some different parameters) this can be a bit of a pain - it's often much more readable to
see the code you're going to execute at the point you use the delegate, and all those extra methods usually do
nothing outside their use for constructing delegates. In addition, if you need to use some context which isn't already
in your object within a delegate implementation (e.g. a local variable), you sometimes need to create a whole extra class to
encapsulate that context. Yuk. Fortunately C# 2.0 has a delegate equivalent to Java's anonymous inner classes - but without
as much mess.

Here's a rough equivalent of the Java code above, this time in C# 2.0:

Now, admittedly part of the reason this is so much shorter is the lack of comments and the way I've included the inline
code without putting line breaks before/after the braces. However, because there's so little to the delegate
definition, I could afford to do that without losing readability.

Similar to Java and anonymous classes, when the C# compiler encounters an anonymous method, it either creates an extra (nested) type
or an extra method within the current type behind the scenes to contain the delegate implementation. It's easy to see
why an extra method would be required - but why would an extra type be needed? It's all to do with captured variables...

This is where things can become slightly difficult. Like many things, captured variables are fabulously useful,
but to start with they can be hard to understand, and they can change some of what you may think you already know about C#.
The purpose of them is very simple though - they're there to make local variables from the method declaring an anonymous method
available within the delegate itself.

Static and instance variables of the class don't need to be captured - normal instance and static methods can be created by the
compiler to access those. However, look at the example given above. How can the delegate "see" the value of args
to print out args[0]? In the code above, it's fairly simple - the delegate is only invoked within the method - but
the delegate could be returned from the method, or passed to another method, or stored in a variable somewhere. Just to
make things concrete, here's an example which does just that:

Here, a local variable is available in MakeDelegate, and the delegate uses that local variable
to print a new random number every time it's invoked. But what's the scope of that variable? Does the variable even
exist outside MakeDelegate? Well, the answer is yes - because the compiler compiles it into an instance
variable in a new type behind the scenes. If you compile the above and look at it with ildasm, you'll see
that there actually isn't a Random local variable in MakeDelegate at all, as far as
the runtime is concerned! Instead, there's a local variable of a nested type with some compiler-generated name (the time I
compiled it, the name was <>c__DisplayClass1). That type has a Random instance variable,
and when rng is assigned or used within MakeDelegate, it's that variable which is actually
used. The method used to implement the delegate signature is a member of the nested type, so it is able to get at
the Random instance even after MakeDelegate has finished executing.

Things become really tricky when there are multiple local variables being used in the delegate, in particular when
some of them are effectively created several times. This is best demonstrated with an example:

Don't worry if it takes you a while to understand the output - it certainly threw me! Look carefully at
where x and y are declared. There's only one x variable for the whole method,
but there's a "new" y variable each time we go through the loop. That means that all the
delegate instances share the same x variable, but each one has a different y
variable. That's why the first number printed keeps going up, but the second number printed only goes up when the same
delegate instance is called again. (If another instance of the delegate was created inside the loop, then each pair
of delegate instances would share the same y variable.) Any access to the variable within the main body
of the method uses the "current" set of variables - so any change to y within the loop itself would
affect just the instance created in that iteration of the loop.

The reason this is contrary to intuition is that usually it doesn't really matter where a variable is declared
within a method (assuming you don't want to use the same name elsewhere in the method, and that you've made the scope
large enough to access it everywhere you want to). The location of the assignments matters, of course, but the actual
declarations have previously only affected the scope of the variable. They now affect the behaviour, as seen above -
the way the values of x and y behave in the delegate instances are very different.

In case you're wondering how some variables are shared and some aren't, in the above code two extra types
are created - one with an x variable, and one with a y variable and another variable
referring to an instance of the first extra type. The delegate implementation is a member of the second type,
and each instance of the second type has a reference to the same instance of the first type. You can imagine
how complicated things must get when even more variables are involved!

As I said before, captured variables are very useful - but they come at the price of readability. Examples like
the code above, where different variables are shared or not shared, should be rare in real code. Anything where
the reader has to work out just where a variable came from and which variables will be associated with which
delegates is going to be a pain at maintenance time.