Before we had async
/await
and Task
-oriented programming, there were async operations exposed on various I/O wrappers (that are still available) using the BeginOperation
/EndOperation
pattern with IAsyncResult
. I'm having difficulty finding documentation around what happens if you never call the EndOperation
part of the contract, especially with regard to unobserved exceptions. I know Task
s take a pretty dim view of unobserved exceptions. What happens if an IAsyncResult
gets disposed while holding onto an exception?
Asked
Active
Viewed 90 times
1

Jonathan Gilbert
- 3,526
- 20
- 28
-
Side note: `Task` is an `IAsyncResult`. A lot of the high-level concepts are the same. If you ignore an `IAsyncResult`, I expect it would behave the same as if you ignored a `Task`. – Stephen Cleary Jun 07 '19 at 19:35
-
You can't dispose IAsyncResult. It used to cause a 10 minute resource leak but they did something about it in CLR v4 and I lost track. Not documenting what goes wrong when you do it wrong does allow for such improvements. You don't have to worry about leaking an exception object, the data associated with the operation is the much bigger chunk. Task used to be more aggressive about reminding programmers that an exception was unobserved but that was too much truth to handle. – Hans Passant Jun 07 '19 at 21:13
-
Well then I guess what happens if it gets finalized? My particular use case was `Socket`'s `BeginConnect`/`EndConnect` methods. I poked at reference source, and as far as I could tell, there actually didn't seem to be any significant resource tied up, nor did the connect operation have a `Dispose` or a finalizer or indeed any means of holding onto an exception. I'm working with an existing codebase that implements cancelling a connect by calling `BeginConnect` and then polling for a cancellation condition. If cancelled, it simply abandons the operation. I'm trying to figure out if that's okay. – Jonathan Gilbert Jun 08 '19 at 08:46
-
That comment wasn't enough characters to properly explain what the existing code is doing. It calls `BeginConnect` to obtain an `IAsyncResult`. Then, it creates a `Task` that loops, waiting on the `IAsyncResult`'s `AsyncWaitHandle` in 100ms increments, and each time that returns with a timeout, it calls `cancellationToken.ThrowIfCancellationRequested`. It then `await`s that `Task`, which I'm assuming the author did because the parent method is `async` and he wants to release the sync context. If the loop exits and the `Task` completes, then `EndConnect` is called. – Jonathan Gilbert Jun 08 '19 at 08:53
-
...but if the cancellation token gets set, it throws an exception and never hits `EndConnect`. – Jonathan Gilbert Jun 08 '19 at 08:53
-
I have reworked my approach substantially. I did a bunch of searching around and found that the only way to cancel a socket's ongoing connection is to close the socket, which of course burns the socket, but hey, that seems to be just what you do. If you're using Begin/End, then `EndConnect` will then throw an exception -- but you still call it. So I created an extension method that ties this up with a `CancellationToken`. https://github.com/logiclrd/IpcServiceFramework/blob/JDG_CorrectlyEndConnectionAsyncOperations/src/JKang.IpcServiceFramework.Client/Tcp/TcpClientExtensions.cs – Jonathan Gilbert Jun 08 '19 at 18:06