>> Since you can't propagate two exceptions >> at the same time, > >Ironically .NET does offer us a way to propagate multiple exceptions -- the >InnerException property gives each exception the potential, effectively, to >represent a linked-list of exceptions (composite design pattern). > >I agree (I think) with you: it would be nice if the CLR could somehow >automatically populate the InnerException, if/when a new exception is >thrown from within a finally block, during a stack-unwind. > >I can't think of any problems that would cause... except, well, if the new >exception already has a chain of inner exceptions. :) But hey, like I >said, it's effectively a linked list. The original exception-chain can >always be tacked on to the end, somehow, right? :/
Is it possible to put a circular reference in the exception hierarchy I wonder? I notice that the InnerException property is read-only and sealed, but there's probably a reflection based way to meddle with it. I'm sure there is plenty of recursive exception reporting algorithms that would stack overflow if you were nasty enough to throw someone such an exception.. as a side note, I remember reading something about the CLR not requiring exceptions to be derived from System.Exception too. Someone commented that 'the object is not constructed' if an exception is thrown from the constructor, but that's not true. It's true that a reference to the new instance is not returned, but the instance is always 'created' (I'm not sure what the definition is 'construction' is in this case, but certainly an object id is allocated, etc.). This is obviously the case, since you have access to the 'this' pointer inside the constructor. I hacked something together to check this out. As a result I've come up with a new coding rule for myself: 'if the constructor is going to throw, then the constructor has to guarantee that it hasn't configured another instance with a reference to itself'. Of course, this is immediately impractical given the way the WinForms designer and InitializeComponent() works. Hmm.. not sure what to do.. In my view, at least to some extent, construction should be 'atomic'. Consider the example below, which leaks references to 'partially constructed' instances to the invocation list of an event. This could cause all sorts of crazy things to happen that would be difficult to diagnose. If you run this code, you'll see three partially constructed classes handle the publisher's event. This is definitely something to watch out for. At the end of the day, I tend to think of exceptions as being too difficult to handle. I design my code such that exceptions don't happen. If they do, then I have a bug and I need to fix it, I don't pretend that I can really 'handle' an exception (obviously there are cases where you have to, but I try to avoid these), despite its politically correct name I still consider it an 'error' and I generally terminate my process. To try and handle all the possible states that you could be in when you receive an exception seems almost impossible to me. John. public class EntryPoint { [STAThread] public static void Main(string[] args) { EventPublisher publisher = new EventPublisher(); EventSubscriber subscriber = null; // construct and detach three subscribers for (Int32 i = 0; i < 3; i++) { try { // try to construct a subscriber subscriber = new EventSubscriber(publisher); } catch { // ignore construction exception } if (subscriber != null) { // construction was successfull, now detatch // NOTE: this won't execute in this example as construction // is never successful, meaning we can't detach the // subscriber subscriber.Detach(); } } // notify all subscribers of publishers event // NOTE: three 'partially constructed' instances will be notifed // although the code on this method tends to indicate that there // should be no subscribers (assuming that construction is 'atomic' // to some extent). publisher.Notify(); Console.ReadLine(); } } public class EventPublisher { public event EventHandler SomeEvent; public void Notify() { this.OnSomeEvent(EventArgs.Empty); } private void OnSomeEvent(EventArgs e) { if (this.SomeEvent != null) this.SomeEvent(this, e); } } public class EventSubscriber { private EventPublisher _publisher; private Boolean _isConstructed; public EventSubscriber(EventPublisher publisher) { // reference publisher this._publisher = publisher; // subscribe to publishers event (has the effect of passing // a reference to to this presently partially constructed // instance to the publisher) this._publisher.SomeEvent += new EventHandler(this.SomeEventHandler); if (this._publisher != null) { // throw an exception during construction // NOTE: this is just for the sake of example throw new ApplicationException(); } // flag construction as successfully completed. // NOTE: this will not be set and the value will remain // defaulted to 'false'. this._isConstructed = true; } public void Detach() { // if still attached, detach from the publisher if (this._publisher != null) { this._publisher.SomeEvent -= new EventHandler(this.SomeEventHandler); this._publisher = null; } } private void SomeEventHandler(Object sender, EventArgs e) { // NOTE: for testing output the hashcode (inherited from Object // as the internal object id) and an indication of successful // instance creation. Console.WriteLine("Instance " + this.GetHashCode() + " handled event. Constructed:" + this._isConstructed); } } =================================== This list is hosted by DevelopMentorŪ http://www.develop.com Some .NET courses you may be interested in: NEW! Guerrilla ASP.NET, 17 May 2004, in Los Angeles http://www.develop.com/courses/gaspdotnetls View archives and manage your subscription(s) at http://discuss.develop.com