Using Exceptions For Normal Logic Flow

The generally accepted wisdom is that you shouldn’t use Exceptions for normal logic flow.  Normal logic flow is a bit subjective; but anything that must happen at least once in all known scenarios is normal logic flow.

Enter XML Serialization in the framework.  The framework actually dynamically creates types that perform the actual serialization of a given type and caches that assembly.  The next time that type needs to be serialized it reuses that generated type, reflection is minimized and things happen pretty quickly.

Here’s the rub.  The framework decides that it must generate the type when Assembly.Load generates an exception.  Something like:

        Assembly assembly = null;

        try

        {

            assembly = Assembly.Load(assemblyName);

        }

        catch (Exception)

        {

            assembly = GenerateTempAssembly();

        }

Which means exceptions are being used for normal logic flow, because when the code is first run the exception is thrown. Now, there’s some folks out there (including folks at Microsoft) that will say “what’s wrong with that, it gets the job done doesn’t it?”.  Yes, it does get the job done.  The problem is there’s at least once that Assembly.Load is going to generate an exception (if you modify the type being serialized it will happen again).  Again, some may say, “So what?”.  Well, in Visual Studio there is a BindingFailure Managed Debugging Assistant (MDA) that sits there looking for Assembly.Load failures.  This will get kicked off and force a break the first time you try to serialize your type and you’re debugging.  When you’re using XmlSerializer to serialize many different types and you turn on this MDA (after all, it’s there and does do some good) then you’ll spend a whole bunch of time wading through the BindingFailure MDA.

This has been occurring since XmlSerializer was created.  I say “including folks at Microsoft”, because up until a couple of days ago I thought someone was on this problem (although I can’t find my sources anymore) at Microsoft.  But, the problem still occurs in Ocras Beta 2; which means in the past 3-4 years no one has done a thing about this problem.  So, I logged a bug about it on Connect (https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304095) and it was quickly closed as “By Design”.

Keep in mind, the “fix” were talking about is simply checking to see if a file exists before trying to load it, something like:

        Assembly assembly;

        try

        {

            Debug.Assert(assemblyName.CodeBase.StartsWith(“file:///”, true, System.Globalization.CultureInfo.InvariantCulture));

 

            String path = assemblyName.CodeBase.Substring(8).Replace(‘/’, ‘\\’);

            if (!System.IO.File.Exists(path))

            {

                assembly = GenerateTempAssembly();

            }

            else

            {

                assembly = Assembly.Load(assemblyName);

            }

        }

        catch (Exception)

        {

            assembly = GenerateTempAssembly();

        }


…not too tricky…

3 thoughts on “Using Exceptions For Normal Logic Flow”

  1. There is still a race condition that could cause an exception to be thrown – between checking for the assemblies existence and generating it, I guess this is why you still have the ‘catch’ statement.

    As for using exceptions for normal logic flow, I believe it’s discouraged because the ‘average’ dev doesn’t understand when it should and shouldn’t be used.

    How about a post on when it’s a good idea to catch ‘System.Exception’ :)

  2. Yes, that’s why the catch is still there. Testing for the existence of the file just mitigates the exception occurring–which effectively eliminates it. You would have to know where these temporary assemblies existed and delete it in the few milliseconds between the check and the load for the exception to occur any more–doubtful that would occur while you’re debugging.

  3. “As for using exceptions for normal logic flow, I believe it’s discouraged because the ‘average’ dev doesn�t understand when it should and shouldn’t be used.”

    But this suggests there ARE times when it is OK to use it for normal logic flow, which is not the case — it offers *zero* advantage to the accepted methods of normal logic flow — zero, zip, null. There is absolutely *no point* in using exceptions for normal logic flow at all.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>