0

I have the following function in my C# helper library which updates an object in a third-part application (CATIA V5):

    public void Update(INFITF.AnyObject objectToUpdate)
    {
        try
        {
            Part.UpdateObject(objectToUpdate);
        }
        catch
        {
            throw new InvalidOperationException("Update Failed");
        }
        finally
        {
            Part.Inactivate(objectToUpdate);
        }
    }

It is unavoidable that Part.UpdateObject() will sometimes fail.

In the case that this fails, I would like to notify the function user that the update failed, give them the opportunity to fix the problem in a custom way and handle the exception, or handle the exception in a default, stable way.

I know that the code I posted won't work because finally blocks don't even get called if an exception is unhandled...but hopefully the code block gets the idea across.

UPDATE:

I haven't explained my scenario well enough so let me clarify. I am writing this function which other people will use as they develop. Some of these programmers know how to use try/catch blocks and some don't. Here are two sample scenarios where the function could be called.

A. the user is familiar with try/catch blocks and is aware of why the update call could fail.

try
{
    Update(objectToUpdate);
}
catch (InvalidOperationException ex)
{
    //fix the problem with the object to update
    //I have handled the exception, so I DO NOT want the object to be inactivated
}

B. the user is not familiar with try/catch blocks or is not aware the update could fail

Update(objectToUpdate)

In this scenario we want to handle a failed update in a stable way that makes sense to a novice programmer and prevents the application from crashing. (in this case, inactivating the offending object in the third-party CAD software)

Eric
  • 1,392
  • 17
  • 37
  • I'd consider raising an event in the catch instead of throwing again. Or let the client handle the retry logic. – AJ X. Nov 30 '16 at 16:34
  • 3
    [A finally block is always executed, regardless of whether an exception is thrown.](https://msdn.microsoft.com/en-us/library/ke0zf0f5(v=vs.110).aspx) – Paul Abbott Nov 30 '16 at 16:34
  • it says here: https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx that a finally block is not executed if an exception is unhandled, is that only true for try-finally blocks and not try-catch-finally blocks? – Eric Nov 30 '16 at 16:38
  • In your case the finally block will be called as any finally block will be (except for [rare situations](http://stackoverflow.com/a/3216109/40347)). Can you explain what part of your code is not working as expected? – Dirk Vollmar Nov 30 '16 at 16:40
  • I don't know how to tell in the finally block if the exception has been handled. I only want to run Part.Inactivate() if the exception is unhandled. – Eric Nov 30 '16 at 16:40
  • 1
    @Eric: That's only for the case that an unhandled exception terminates your application (and in that case running the finally code usually doesn't matter anymore). If you handle the exception somewhere in your callstack, then the finally is guaranteed to be executed. – Dirk Vollmar Nov 30 '16 at 16:41
  • This is an API of sorts, so I cannot be sure the exception will be handled. – Eric Nov 30 '16 at 16:42
  • "I don't know how to tell in the finally block if the exception has been handled" - just set a flag in your Catch code – peterG Nov 30 '16 at 16:42
  • and have the user of the Update call flip the flag? I don't see how that works – Eric Nov 30 '16 at 16:43
  • If you catch a *specific type only* then another type of `Exception` may be unhandled in your `finally`. i.e. `catch (IOException)` and the `Exception` thrown was of type `ArgumentException`. The code you posted catches all cases. – toadflakz Nov 30 '16 at 16:44
  • is there an exception type that just doesn't kill my application, so it's ok if it goes unhandled? – Eric Nov 30 '16 at 16:45
  • Your `catch` block catches all exceptions so it's not possible for the exception to be unhandled. If you have a specific exception type you can add a `catch (Exception ex)` block after your specific handler and put the unhandled code in there. – Lee Nov 30 '16 at 16:46
  • what about the exception I am throwing? If that goes unhandled will the application crash or does the finally block handle it? – Eric Nov 30 '16 at 16:47
  • "and have the user of the Update call flip the flag? I don't see how that works " Clear the flag in the Try section. Set the flag in the catch. If you hit the Finally with the flag still clear, then you have not had an exception. Obviously you can extend this model to multiple catches for multiple exception types. – peterG Nov 30 '16 at 16:52
  • that doesn't sounds like a great option because it would depend on the user knowing about and clearing the flag correctly. – Eric Nov 30 '16 at 18:35
  • What I've done is to create a HandledException class with a built in flag – Eric Nov 30 '16 at 18:48
  • By 'user' I don't know if you mean the actual user or the calling code. However, neither of these would need to interact with the flag; the flag's initial condition is set on entry to the function. – peterG Nov 30 '16 at 23:53

2 Answers2

0

Unhandled exception is the one that is not "handled" by the calling routine i.e. it is not caught by any part of the code. In your case ALL the exceptions are caught except the ones that may be somehow hardware, driver, device or memory related in which case the application will be terminated by the OS. Not much you can do about that. You may try to create the AppDomain UnhandledException handler to try to get some information on the application shutdown, but this may not always work if the OS killed your app.

Ezra
  • 49
  • 4
  • This answer does not provide a way for the finally code to not run if the exception is handled. – Eric Nov 30 '16 at 18:37
0

The discussion has been helpful, in particular the flag idea. That said, the flag needs to be manipulated from the calling code so here is my solution:

First I created a HandledException class:

[Serializable()]
public class HandledException : Exception
{
    public bool Handled { get; set; }

    public HandledException(string Message)
        : base(Message)
    {

    }
}

I then changed my Update method to be as follows:

[DebuggerHidden]
public void Update(INFITF.AnyObject objectToUpdate)
{
    HandledException ex = new HandledException("Update Failed");
    bool updateSuccesful = false;
    try
    {
        Part.UpdateObject(objectToUpdate);
        updateSuccesful = true;
    }
    catch
    {
        throw ex;
    }
    finally
    {
        if (!updateSuccesful && !ex.Handled)
        {
            if(!Part.IsUpToDate(objectToUpdate))
                Part.Inactivate(objectToUpdate);
        }
    }
}

This only tries to inactivate the CAD object if the update has failed and allows the calling code to handle the exception and prevent object inactivation.

If the user does not handle the failed update, the problem is dealt with in a stable way.

Sample usage:

try
{
    partDoc.Update(pad);
}
catch (HandledException ex)
{
    //I want the pad to be deactivated so I continue with the default behavior
    //in some scenarios I would fix the pad and mark the exception handled
    ex.Handled = false;
    string currentName = currentBody.get_Name();
    currentBody.set_Name(currentName + "_PadError");
}

Thank you for the discussion, sometimes you just need to talk through a problem :)

Eric
  • 1,392
  • 17
  • 37