Sometimes I could be convenient to know if IDisposable implementation is already disposed without exercising some try/catch about ObjectDisposedException or other/similar cases.
Instance:
var request = (HttpWebRequest)WebRequest.Create("http://www.seznam.cz");
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
using (var streamReader = new StreamReader(responseStream))
{
responseStream.ReadByte();
WriteLine("responseStream: " + responseStream.CanRead);
}
WriteLine("responseStream: " + responseStream.CanRead);
responseStream.ReadByte();
}
}
responseStream: True
responseStream: False
The request was aborted: The connection was closed unexpectedly.
+ System.Net.ConnectStream.Read(byte[], int, int)
+ System.IO.Stream.ReadByte()
Instead of rely on exact implementation one could easily extract information needed from bool property.
interface IDisposableExt : IDisposable {
bool AlreadyDisposed { get; }
}
To prevent braking change this could be new interface implementing IDisposable.
Implementation
Yet nowadays developer is responsible for implementing IDisposable pattern properly. Specifically: call _GC.SuppressFinalize(this)_, release object resources only once, handle finalizer/consumer call case and further more responsibilities on this. Regard this pattern there already exists private field bool disposed.
private bool disposed = false;
Since that transforming such a private bool field to public bool property is little-effort change in responsibility (IDisposable pattern).
bool AlreadyDisposed { get; }
The proposed new property allows you to ask the question "Has someone already disposed this or should i do it?". Needing to ask this question means that the movement of the resource through the program is not clearly defined in some way. You'll end up with something at the end of pipelines doing cleanup that should have been done by the known owning party. This feels like something you would put in place to mitigate rather than fix bugs, it's like a user GC phase to make sure resources are freed eventually when the best answer is to free the resources deterministically.
Dispose implementations can be made non throwing and idempotent if you need them to be so there is no requirement to use try catch unless you're using a library that chooses to throw, if you have a library that has chosen to throw and you're multiply disposing it sound like you aren't using the library as intended.
The issue is that one can use this property to avoid multiple Dispose calls let say in nested usings in a way it is possible to easily check if object of inner using disposed “upper“ object. I mean in development phase.
Rule CA2022 discourages relying on harmless idempotent implementations. Nonetheless I read your advice.
Strictly speaking when I’m verifying 3rd party object/class without verbose documentation provided, I cannot distinguished between disposed and unreadable stream. Technically I have no plump information why stream is unreadable. It is obvious it is disposed. That’s for sure.
It was/is improvement just about expected reliable approach regard disposed state.
I mean in development phase
I don't know if is applicable but "in development phase" usually I use debug assertion to be sure of the semantics.
I mean in development phase
I don't know if is applicable but "in development phase" usually I use debug assertion to be sure of the semantics.
Not exactly. Each object has “its way” how to express that is disposed. So issue is not about what approach to choose but where to find the information.
The issue is that one can use this property to avoid multiple Dispose calls let say in nested usings in a way it is possible to easily check if object of inner using disposed “upper“ object.
This is what @Wraith2 was talking about - in such a situation, your ownership is confused. (This is why Rust does what it does).
This coulld also be done now with default interface implementations I believe.
Most helpful comment
The proposed new property allows you to ask the question "Has someone already disposed this or should i do it?". Needing to ask this question means that the movement of the resource through the program is not clearly defined in some way. You'll end up with something at the end of pipelines doing cleanup that should have been done by the known owning party. This feels like something you would put in place to mitigate rather than fix bugs, it's like a user GC phase to make sure resources are freed eventually when the best answer is to free the resources deterministically.
Dispose implementations can be made non throwing and idempotent if you need them to be so there is no requirement to use try catch unless you're using a library that chooses to throw, if you have a library that has chosen to throw and you're multiply disposing it sound like you aren't using the library as intended.