First of all, good question. I admire your focus on utility rather than blindly accepting "best practices". +1 for that.
I've read that guide before. You have to remember something about it - it is just a guide, mainly for C# newcomers who know how to program but aren't so familiar with the C# way of doing things. It's not so much as a page of rules as it is a page that describes how things are already usually done. And since they're already done this way everywhere, it might be a good idea to stay consistent.
I'll get to the point, answering your questions.
First of all, I assume you already know what an interface is.
As for a delegate, it's enough to say that it's a structure containing a typed pointer to a method, along with an optional pointer to the object representing the this
argument for that method. In case of static methods, the latter pointer is null.
There are also Multicast delegates, which are just like delegates, but may have several of these structures assigned to them (meaning a single call to Invoke on a multicast delegate invokes all of the methods in its assigned invocation list).
What do they mean by an eventing design pattern?
They mean using events in C# (which has special keywords for sophistically implementing this extremely useful pattern). Events in C# are fueled by multicast delegates.
When you define an event, such as in this example:
class MyClass {
// Note: EventHandler is just a multicast delegate,
// that returns void and accepts (object sender, EventArgs e)!
public event EventHandler MyEvent;
public void DoSomethingThatTriggersMyEvent() {
// ... some code
var handler = MyEvent;
if (handler != null)
handler(this, EventArgs.Empty);
// ... some other code
}
}
The compiler actually transforms this into the following code:
class MyClass {
private EventHandler MyEvent = null;
public void add_MyEvent(EventHandler value) {
MyEvent += value;
}
public void remove_MyEvent(EventHandler value) {
MyEvent -= value;
}
public void DoSomethingThatTriggersMyEvent() {
// ... some code
var handler = MyEvent;
if (handler != null)
handler(this, EventArgs.Empty);
// ... some other code
}
}
You then subscribe to an event by doing
MyClass instance = new MyClass();
instance.MyEvent += SomeMethodInMyClass;
Which compiles down to
MyClass instance = new MyClass();
instance.add_MyEvent(new EventHandler(SomeMethodInMyClass));
So that's eventing in C# (or .NET in general).
How the composition turns out to be easy if a delegate is used?
This may easily be demonstrated:
Suppose you have a class that depends on a set of actions to be passed to it. You could encapsulate those actions in an interface:
interface RequiredMethods {
void DoX();
int DoY();
};
And anyone who wanted to pass actions to your class would first have to implement that interface. Or you could make their lives easier by depending on the following class:
sealed class RequiredMethods {
public Action DoX;
public Func<int> DoY();
}
This way the callers only have to create an instance of RequiredMethods and bind methods to the delegates at runtime. This is usually easier.
This way of doing things is extremely beneficial under the right circumstances. Think about it - why depend on an interface when all you really care about is having an implementation passed to you?
Benefits of using interfaces when there are a group of related methods
It's beneficial to use interfaces because interfaces normally require explicit compile-time implementations. This means that you create a new class.
And if you have a group of related methods in a single package, it's beneficial to have that package be reusable by other parts of the code. So if they can simply instantiate a class instead of building a set of delegates, it's easier.
Benefits of using interfaces if a class only needs one implementation
As noted earlier, interfaces are implemented in compile time -- which means they are more efficient than invoking a delegate (which is a level of indirection per se).
"One implementation" might mean an implementation that exists a single well-defined place.
Otherwise an implementation might come from anywhere in the program which just happens to conform to the method signature. That allows for more flexibility, because methods need only to conform to the expected signature, rather than belong in a class that explicitly implements a specific interface. But that flexibility might come at a cost, and actually breaks the Liskov Substitution principle, because most times you want explicitness, because it minimizes the chance for accidents. Just like Static Typing.
The term might also refer to multicast delegates here. Methods declared by interfaces can only be implemented once in an implementing class. But delegates can accumulate multiple methods, which will be called sequentially.
So all in all, it looks like the guide is not informative enough, and merely functions as what it is - a guide, not a rulebook. Some advice might actually sound a bit contradictive. It's up to you to decide when it's right to apply what. The guide seems to only give us a general path.
I hope your questions have been answered to your satisfaction. And again, kudos for the question.