问题
I have a class which implements IDisposable interface.
using System;
class A : IDisposable
{
public void Dispose()
{
Stop(); // some actions to stop internal threads
this = null;
}
}
Why can't I assign this = null
in Dispose method ? I know 'this' is read-only.
For example:
A a = new A();
a.Run();
// ...
a.Dispose();
// i want in this line a = null
I thought IDisposable and Dispose method guarantee that instance of class A will be equals to null after calling Dispose(). But it's not true.
回答1:
Just to add to what's already been said:
It's important to realize that there are objects, and there are references (variables), and these are not the same thing.
When you write var a = new object();
you're doing two things:
- Creating a new
object
instance. This instance has no "name" -- just a location in memory. It is what it is. But, just so we have something to call it, let's call it "Bob." - Declaring a variable
a
, which references theobject
just created.
Now, when you write a = null;
, you're doing nothing to Bob. You're changing a
to reference, instead of Bob, null
, or in other words, "no object." So you can no longer access "Bob" using a
.
Does this mean now Bob doesn't exist? No. Bob's still right where he was.
Consider this (which is basically the scenario Henk mentioned):
var a = new object(); // Again, we're calling this object Bob.
object b = a;
Now, b
is another variable, just like a
. And just like a
, b
references Bob. But again, just as with a
, writing b = null;
does nothing to Bob. It just changes b
so that it no longer points to an object.
Here's where I'm going with this. You seem to have been under the impression that doing this:
a.Dispose();
...somehow also did this:
a = null;
...which was somehow equivalent to doing this:
Bob
= null; // now
Bob
is no object?
But if that were the case, then b
(above) would now point to no object, even though it was never set to null
!
Anyway, from my explanation above, hopefully it is clear that this is simply not how the CLR works. As Jon has pointed out, the IDisposable
interface is actually not related to memory being freed. It is about releasing shared resources. It does not -- cannot -- delete objects from memory, as if it did then we would have the behavior I've described above (references suddenly becoming invalid out of nowhere).
I know this was only loosely related to your specific question about IDisposable
, but I sensed that this question was coming from a misconception about the relationship between variables and objects; and so I wanted to make that relationship clearer.
回答2:
No, Dispose
is just a method like any other method as far as the CLR is concerned. C# has support for it via using
statements (and foreach
with the iterator being disposed), but other than that it has no significance. In particular, it doesn't directly interact with the garbage collector, or affect any variables referring to the disposed object. (Some implementations of IDisposable
may also have finalizers which call Dispose
, but they're logically distinct concepts.)
Note that an object isn't necessarily unusable after being disposed. For example, disposing of a MemoryStream
doesn't clear out the data in memory - using ToArray
on it afterwards will still work.
Indeed, the documentation for IDisposable explicitly talks about the possibility of it being used to reset an object for reuse:
Use this method to close or release unmanaged resources such as files, streams, and handles held by an instance of the class that implements this interface. By convention, this method is used for all tasks associated with freeing resources held by an object, or preparing an object for reuse.
回答3:
It is not possible but also not useful.
Consider b
in:
A b = a; // alias
a.Dispose();
// i want in this line a = null
And it's not really a problem, there still is an object that a
and b
reference to. It just has its internal state changed to 'closed'. Some IDisposable classes have a bool IsDisposed
member that you can safely call after Dispose()
回答4:
Your assumption is incorrect. Dispose()
doesn't reclaim the instance and doesn't affect the reference.
It is a utility method that gets some special attention from the framework/compiler that allows you to easily clean up resources not handled by the GC. Other than that it is just a regular method. Calling a method should not affect the reference itself.
The recommendation for implementing Dispose()
specifically states
To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception.
来源:https://stackoverflow.com/questions/3649573/clarify-some-things-about-idisposable-interface-is-instance-must-be-equals-nu