Search code examples
c#windows-runtimeuwpdatareader

Handle Exception that happens within a using statement (IDisposable)


I'm using the DataWriter and DataReader interfaces. These classes have the IDisposable interface implemented, therefore I wrap them around the using keyword:

using(var datareader = new DataReader(SerialPortInputStream))
{
CancellationTokenSource cancellation = new CancellationTokenSource();
//Timeout
cancellation.CancelAfter(1000);
//...
datareader.LoadAsync(120).AsTask(cancellation.Token);
//Some fancy methods
...
//Last step: Detach the InputStream to use it again
datareader.DetachStream();
}

This thread here is saying that if an Exception (here a "TaskCancelledException" happens inside a using statement, the object gets disposed. Now, the problem is with the UWP-DataReader and DataWriter: They will close the underlying stream if the object gets disposed. To prevent that I've to call datareader.DetachStream() and then dispose.

We cannot use the DataReader/DataWriter with a using statement when we need the underlying InputStream/Outputstream later again. Is this conclusion correct or are there other ways to handle this situation?


Solution

  • The whole meaning of using is to make sure that the object gets disposed at the end of the block no matter what happens without having to write all the code for this by yourself. This is done by disposing the object inside a finally block.

    What you are trying to do is to call datareader.DetachStream() before the object gets disposed - again no matter what happens.

    So my conclusion would be that the using statement isn't very helpful here and you should do this by yourself, maybe like this:

    DataReader datareader = null;
    try
    {
        datareader = new DataReader(SerialPortInputStream);
        CancellationTokenSource cancellation = new CancellationTokenSource();
        //Timeout
        cancellation.CancelAfter(1000);
        //...
        datareader.LoadAsync(120).AsTask(cancellation.Token);
        //Some fancy methods
        ...
    }
    finally
    {
        //Last step: Detach the InputStream to use it again
        datareader?.DetachStream();
        datareader?.Dispose();
    }
    

    So this is essentially what the using statement does to your code, except that you can insert the datareader?.DetachStream() call.


    Note that the datareader would eventually get disposed anyway even without the using statement. When the scope of this variable is left, the garbage collection may anytime decide to remove this instance from memory which would lead to a call to its Dispose method. So a call to DetachStream() is needed before leaving the scope.