I had been working on a base class for reading and writing to a database. I knew that when a new object (and hence record) was created there needed to be a mechanism for setting default values. I also knew that even with the default values there might not be enough information that the object could be saved.
For example: In a contact database, a new contact would by default have a blank name and blank phone number. Trying to save such a contact should not succeed and instead notify the user about the failure. Too many applications and web pages do this one failure at a time. I wanted to be able to cover all of the failures in one step.
This presents an interesting problem in any user interface. How can an object notify the environment about multiple failures? The standard way to notify the environment about any failure is to throw an exception. But I wanted to throw multiple exceptions and have them all be handled at one time. So was born the idea of a
MultiException object should itself act as an Exception, but it should also act as a Collection. This way, when a save occurs, the data class has the ability to add exceptions to the
MultiException and then throw the
MultiException. The application can then catch the
MultiException and enumerate all of the Exceptions displaying the reason for each one to the end user.
MultiException class turned out to be more of a chore then I originally thought. The easiest way to create a class that acts as a collection is to base it on the
CollectionBase class. The problem with this approach was that I wanted
MultiException to be based on
ApplicationException and .Net only allows us one base class. .Net does, however, allow for a class to be based on one class and multiple interfaces.
MultiException was created based on
ApplicationException but also implements
IList. Being based on
ApplicationException means that
MultiException can be thrown as an exception. Implementing
IList means that new exceptions can be added, gives us the ability to use indexes ( the [ ] operator ), and even allows us to use
Basing the class on
ApplicationException was the easy part. Implementing
IList was a bit more vague. It's not that implementing an interface is difficult, it's just that I didn't want to expose the
IList interface. Why not, you ask? Because the
IList interface is far too generic.
IList interface includes methods like:
public int Add(object O)
public object this[int index]
Obviously we want to add Exceptions and Exceptions only, but the
Add method of the
IList interface accepts any old object. Sure we could test the object as it's passed in and throw an ArgumentException, but it just doesn't look nice and moreover doesn't enforce type-safety.
The obvious answer is to type our Add method correctly:
public int Add(Exception E)
But the compiler will balk at you twice for this move! It will tell you first that the
Add method of
IList isn't implemented and second that the closest match doesn't have the right arguments.
What about making the generic version private? Nope, no good there. The compiler won't accept it as private either which is rightly so. How would anything access the method if we cast our object as an
So then how do we do this right? It actually took me quite a while to find this one (it's easy to overlook). The trick is that you prefix the name of the interface to the generic version, and you make your type-safe version public. Example:
int IList.Add(object O)
public int Add(Exception E)
Notice how you don't even mark the prefixed version public or private. C# understands that the prefixed version is there only to suffice the interface which makes this method operate in a special way. The prefixed version is used while the object is cast as an
IList, but isn't even available while the object is a standard
MultiException any time I have more then one error to report, and hiding implementation members is a hard-to-find trick. I hope you'll be able to use both in your future projects.