Good. At this point we know everything about exception types, what they are, how to obtain them, how to compare them (at least directly). All of these have suddenly become relevant now that we have GETLASTERROROBJECT function in NAV 2015.
But an old friend is still around, the GETLASTERRORCODE function, what about it? Why do we need to bother with GETLASTERROROBJECT when we have a simpler approach, with less peeking into inner exceptions, less reflection, less spooky, obscure .NET internals?
To explain why GETLASTERROROBJECT is better, I’ll go back to the example from my original post. Take a look at this codeunit:
So, there are six possible ways how this piece of code can fail. Let’s now take a look at the proper handling of this code with the help from both GETLASTERRORCODE and GETLASTERROROBJECT.
First, let’s do it the simpler way, the GETLASTERRORCODE. This is what your end result could look like:
When you take a look at it, it seems elegant and simple. The GETLASTERRORCODE function returns a language-independent value, which is unique for most practical purposes.
On another hand, if you want to do it using GETLASTERROROBJECT, then your C/AL takes on more Shakespearean rhetoric:
Of course, if you want to do it the right way, then you should choose the second option, the more complicated one. Why is it so? It’s very simple: it’s the only option guaranteed to unambiguously identify exceptions of different types, because it compares the type of the exception, not the name.
I’ve mentioned earlier that the GETLASTERRORCODE function returns a value that is “unique for most practical purposes”. I really mean that it does not necessarily return a unique value, making it possible that it returns the same value for two or more different exceptions. To understand how exactly it can return the same value for two (or more) different types, let’s first extend our error codeunit with two more error cases, this time throwing a .NET error, not a C/AL one:
To properly handle them using GETLASTERRORCODE, I’d have to write this:
When a .NET error occurs, the code is DotNetInvoke:<exception_name>, where exception_name is the type name of the exception, without the namespace and without the trailing Exception suffix. So, the FileNotFound from the first case above really comes from the System.IO.FileNotFoundException.
Now, imagine that you create two classes in C# and deploy them to NAV:
And then let me extend the error codeunit even further:
We have no way of distinguishing between the System.IO.FileNotFoundException and the two new FileNotFoundException types from two different namespaces. For all three of them, the GETLASTERRORCODE returns the same value: DotNetInvoke:FileNotFound.
However, by using the GETLASTERROROBJECT, you catch just the right type, you only need to add more poetry to the exception handling routine:
(click the screenshots to see them in full resolution)
Just in case the types are not obvious, this is the Globals declaration window:
And of course, when you run your error handling code, it properly catches all three of the exception types, which would otherwise be ambiguous if you attempted to handle this using the GETLASTERRORCODE function:
I am not quite sure exactly why Microsoft has included the GETLASTERROROBJECT function to the C/AL language, and whether it was just because they wanted us to get access to the InnerException, or because they wanted us to unambiguously identify different exception types. I am pretty sure I’d find the answer if I took a look into the Application Test Toolset for NAV 2015, which I couldn’t locate on PartnerSource yet – either it’s not yet published, or just call me lazy.
I hope you enjoyed this series of four posts about exception handling, and I hope you find it useful. If not, just plain tell me I suck – I deserve to know.
Vjeko, what did you do with the “EXIT(TRUE)” part of the InnerExceptionOfType function?