Given that \'most\' developers are Business application developers, the features of our favorite programming languages are used in the context of what we
Delegates become extremely powerful when you start looking at them as functional constructs
.Net 2.0 included support for anonymous delegates, which formed the kernel of some of the functional concepts which were expanded upon by Linq. The syntax for an anonymous delegate is a bit bulkier than what Lambda's offer, but a lot of the core functional patterns are there in 2.0.
In the List generic type you have the following items you can work with:
Appart from List specific items, when your using anonymous delegates context is handled correctly, so you can implement Closure like structures. Or, on a more practicle level do something like:
ILog logger = new Logger();
MyItemICareAbout.Changed += delegate(myItem) { logger.Log(myItem.CurrentValue); };
And it just works.
There is also the DynamicMethod stuff, which allows you to define bits of IL (using Reflection.Emit), and compile them as delegates. This gives you a nice alternative to pure reflection for things like Mapping layers, and data access code.
Delegates are really a construct that allows you to represent executable code as data. Once you get your head around what that means, there are a whole lot of things that can be done. The support for these constructs in 2.0 was rudimentary when compared to 3.5, but still there, and still quite powerful.