Delegates provide a type-safe and object-oriented way to manage callbacks into methods that have a specific signature. Situations that called for function pointers or callback methods in C and C++ are perfect candidates for delegates, which are type-safe and more flexible than function pointers. Delegates used in C# are based on the .NET Framework’s MulticastDelegate class, which allows delegate methods to be multiplexed into a chain of methods that are invoked sequentially.
Events are used for one-way notifications between an event supplier and a client. Although events are based on delegates, they’re not appropriate for cases in which the client needs to pass a return value or a reference parameter back to the supplier.
Finally, attributes provide a unique way for you to declaratively add functionality to your code by adorning your program’s elements. By subclassing the System.Attribute class, you can create your own attributes.