If you design libraries for internal or external usage one of the main concerns should be if extensibility should be provided. I‘d like share some thoughts on events/callbacks, the seal keyword and some considerations on exception handling.

Use events only when users need to customize the behavior of your objects without the need for them to understand their object model/internal working. One of the ugliest examples about this I’ve seen so far is the way the Telerik ASP.Net controls use events in the client side to limit the filter options displayed for a given column. Basically if you want to limit the filter options per column in JavaScript you need to intercept an event and iterate through all filter items in order to pick the ones you need. The following mumbo-jumbo code (taken from here on 12/Nov/2012) describes the previous sequence:


protected void RadGrid1_Init(object sender, System.EventArgs e)
{
 GridFilterMenu menu = RadGrid1.FilterMenu;
 int i = 0;
 while (i < menu.Items.Count)
 {
 if (menu.Items[i].Text == "NoFilter" || menu.Items[i].Text == "Contains" || menu.Items[i].Text == "EqualTo" || menu.Items[i].Text == "GreaterThan" || menu.Items[i].Text == "LessThan")
 {
 i++;
 }
 else
 {
 menu.Items.RemoveAt(i);
 }
 }
}

In the previous bad sample it was necessary to know the filter menu/menu items’ structure and the page language. Maybe a property it could be better, something like:


RadGrid1.SetVisibleFilters(FilterOPtions.NoFilter, FilterOptions.EqualTo);

An alternative way is using callbacks. Although callbacks are not suitable for the previous sample I’d like to comment that using them is good when high performance is not a concern. If performance is a concern use virtual members. By other hand events are easier to understand for a broader audience and they’re like a broadcast to unknown/uncontrolled consumers. The event sender regains control after the last event handler is executed while a callback gains control after each call. The downside is that callback callers receive consumer’s errors.

Seal your class (using the seal keyword) if you have a good reason to do it. Don’t catch generic expections (i.e.: System.Exception and System.SystemException) in your library code. After shipping your API, do not add members to an interface (otherwise you’ll break your consumer’s code) and do not treat static classes as a miscellaneous bucket.

Further information on:

Events vs. Callbacks here

API design here.

Cheers,

Javier Andrés Cáceres Alvis

Microsoft Most Valuable Professional – MVP
Intel Black Belt Software Developer