I know that catching all exceptions in an app is generally bad, but in my WPF app I do:
Application.Current.DispatcherUnhandledException += (s, e) => {
ReportException(e.Exception, false);
e.Handled = true;
};
This is mostly useful to prevent minor features (like drag&drop) and async code from crashing the app - I log & display the info to the user.
I want to do the same thing in Xamarin.Mac, but there doesn't seem to be an equivalent. I tried:
AppDomain.CurrentDomain.UnhandledException += (sender, args) => Log(args.Exception);
TaskScheduler.UnobservedTaskException += (sender, args) =>
{
args.SetObserved();
Log(args.Exception);
};
Runtime.MarshalManagedException += (sender, args) => Log(args.Exception);
Runtime.MarshalObjectiveCException += (sender, args) => Log(args.Exception);
But when crashing in an async void
method, TaskScheduler.UnobservedTaskException
, MarshalManagedException
and MarshalObjectiveCException
are not called,
and AppDomain.Current.UnhandledException
's e.IsTerminating
is get-only, so I can't prevent the app from exiting.
For Android there's AndroidEnvironment.UnhandledExceptionRaiser += AndroidEnvironmentOnUnhandledException;
But for Mac there doesn't seem to be a way to cancel the app going down?
Unlike Javascript, native MacOS/iOS development is not exception safe and discourages recovering from exceptions as stated in Native iOS docs here:
The standard Cocoa convention is that exceptions signal programmer error and are not intended to be recovered from. Making code exceptions-safe by default would impose severe runtime and code size penalties on code that typically does not actually care about exceptions safety. Therefore, ARC-generated code leaks by default on exceptions, which is just fine if the process is going to be immediately terminated anyway. Programs which do care about recovering from exceptions should enable the option.
There is a way of rejecting exceptions from being thrown by adding a command during compile time, as it is stated in the same link above.
Unfortunately, since Xamarin is Native development, you are stuck to the limitations of native development. The solution is really not to allow exceptions being raised in programming, by using comparisons if (x != null)
or functions like TryParse
, and to only use try-catch in the highest level when absolutely needed.
So even if you try, as shown here, you will not be able to prevent a crash, but you can add logs before the app will certainly crash. Here's another good resource for this, that explains it for native developers.