You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Optionally wrap Java exceptions in BCL exceptions (#3855)
Fixes: #3841
Context: #3646
There are many types provided by Xamarin.Android which subclass
Base Class Library (BCL) types or implement BCL interfaces, such as
`Android.Runtime.InputStreamInvoker`, which inherits
`System.IO.Stream`, or `Android.Runtime.JavaDictionary`, which
implements `System.Collections.IDictionary`.
Unfortunately, there is a long-standing bug in all of these types:
they don't conform to BCL documentation regarding which exception
types may be thrown.
For example, `Stream.Read()` is documented as potentially throwing
`System.IO.IOException` in certain circumstances.
`InputStreamInvoker.Read()`, meanwhile, will *never* throw
`System.IO.IOException` but *can* throw `Java.IO.IOException`
(which does not and cannot inherit `System.IO.IOException`).
The result is that if you have code which expects documented BCL
semantics, e.g. throws `System.IO.IOException`, that code
*may not work as expected* when running within Xamarin.Android.
This is particularly problematic if such code is e.g. a .NET Standard
library, in which case it *cannot* know about Java exception types.
(It could catch `System.Exception`, but this may be undesirable.)
Furthermore, "just fixing" the Xamarin.Android types so that they
properly conform to documented exception behavior means that
*existing* Xamarin.Android apps may break, as they may be catching
the (currently thrown) Java types but not the BCL types.
This makes for a [catch-22][0]: either way we go, *somebody* breaks.
Begin to square this circle:
1. Introduce a new `$(AndroidBoundExceptionType)` MSBuild property
to control which set of exception types may be thrown from
methods overriding or implementing .NET methods, and
2. Publicly document when the default value will change.
The `$(AndroidBoundExceptionType)` MSBuild property accepts one of
two possible string values:
* `Java`: Certain Xamarin.Android methods which override or
implement BCL methods may throw `Java.Lang.Throwable`-derived
instances.
For example, `InputStreamInvoker.Read()` may throw
`Java.IO.IOException`.
* `System`: Certain Xamarin.Android methods which override or
implement BCL methods will *not* throw `Java.Lang.Throwable`-
derived instances.
In this case, the thrown exception will contain the original
Java exception in the `Exception.InnerException` property.
For example, `InputStreamInvoker.Read()` may throw
`new System.IO.IOException(e.Message, e)`, where `e` is a
`Java.IO.IOException`.
In Xamarin.Android 10.5 (to be released with Visual Studio 16.5), the
default value will be `Java`. This is semantically consistent with
all previous Xamarin.Android releases.
[When .NET 5 is released with Xamarin.Android support][1], the
default value will be `System`. This is anticipated to be Fall 2020.
Note in particular the "methods which override or implement BCL
methods" wording: we will *not* alter the exception types which may
be thrown from e.g. [`Activity.SystemorResult()`][2], as that
method doesn't override or implement a BCL method.
[0]: https://en.wikipedia.org/wiki/Catch-22#Concept
[1]: https://devblogs.microsoft.com/dotnet/introducing-net-5/
[2]: https://developer.android.com/reference/android/app/Activity.html#startActivityForResult(android.content.Intent,%20int)
0 commit comments