Here is the scenario:
I have an object called a Transaction that needs to make sure that only one entity has permission to edit it at any given time.
In order to facilitate a long-lived lock, I have the class generating a token object that can be used to make the edits.
You would use it like this:
var transaction = new Transaction();
using (var tlock = transaction.Lock())
{
transaction.Update(data, tlock);
}
Now, I want the TransactionLock class to implement IDisposable so that its usage can be clear. But, I don't have any unmanaged resources to dispose. however, the TransctionLock object itself is a sort of "unmanaged resource" in the sense that the CLR doesn't know how to properly finalize it.
All of this would be fine and dandy, I would just use IDisposable and be done with it.
However, my issue comes when I try to do this in the finalizer:
~TransactionLock()
{
this.Dispose(false);
}
I want the finalizer to release the transaction from the lock, if possible. How, in the finalizer, do I detect if the parent transaction (this.transaction) has already been finalized?
Is there a better pattern I should be using?
Also, the Transaction class itself needn't be disposable, because it doesn't maintain a reference to the lock, and doesn't care whether or not it is unlocked when it goes to the grave.
The Transaction class looks something like this:
public sealed class Transaction
{
private readonly object lockMutex = new object();
private TransactionLock currentLock;
public TransactionLock Lock()
{
lock (this.lockMutex)
{
if (this.currentLock != null)
throw new InvalidOperationException(/* ... */);
this.currentLock = new TransactionLock(this);
return this.currentLock;
}
}
public void Update(object data, TransactionLock tlock)
{
lock (this.lockMutex)
{
this.ValidateLock(tlock);
// ...
}
}
internal void ValidateLock(TransactionLock tlock)
{
if (this.currentLock == null)
throw new InvalidOperationException(/* ... */);
if (this.currentLock != tlock)
throw new InvalidOperationException(/* ... */);
}
internal void Unlock(TransactionLock tlock)
{
lock (this.lockMutex)
{
this.ValidateLock(tlock);
this.currentLock = null;
}
}
}
And the Dispose(bool) code for the TransactionLock:
private void Dispose(bool disposing)
{
if (disposing)
{
if (this.Transaction != null)
{
this.Transaction.Unlock(this);
this.Transaction = null;
}
}
}
This was discussed before. Your case is much easier though, you are also implementing the finalizer. That's fundamentally wrong, you are hiding a bug in the client code. Beware that finalizers run on a separate thread. Debugging a consistent deadlock is much easier than dealing with locks that disappear randomly and asynchronously.
Recommendation: follow the .NET framework lead: don't help too much. Microsoft abandoned the Synchronized method for the same reason.
How, in the finalizer, do I detect if
the parent transaction
(this.transaction) has already been
finalized?
This is possible by keeping a _disposed boolean field in Transaction and exposing it through an IsDisposed read-only property. This is standard practice.
~TransactionLock()
{
this.Dispose(false);
}
Is there a better pattern I should be
using?
If it is correct that TransactionLock has no unmanaged resources then just omit the destructor (finalizer). It has no function but it does have a considerable cost.
Edit: If I read correctly, Unlock does not cut the link from TransactionLock to TTransaction, meaning that an old locks Dispose(bool) will be called though the destructor. It's not clear if that is safe.
The question would be a bit more complete with the code of TransactionLock.Dispose(bool)
Also, the Transaction class itself
needn't be disposable, because it
doesn't maintain a reference to the
lock, and doesn't care whether or not
it is unlocked when it goes to the
grave.
From this it follows that when a TransactionLock is collected, it could only be holding a ref to a Transaction that is also being collected. No need to interfere with destructors here, that would not solve anything and could only create problems you don't need.
Related
Where to call Dispose() for IDisposable objects owned by an object?
public class MyClass
{
public MyClass()
{
log = new EventLog { Source = "MyLogSource", Log = "MyLog" };
FileStream stream = File.Open("MyFile.txt", FileMode.OpenOrCreate);
}
private readonly EventLog log;
private readonly FileStream stream;
// Other members, using the fields above
}
Should I implement Finalize() for this example? What if I do not implement anything at all? Will there be any problems?
My first thought was that MyClass should implement IDisposable. But the following statement in an MSDN article confused me:
Implement IDisposable only if you are using unmanaged resources directly. If your app simply uses an object that implements
IDisposable, don't provide an IDisposable implementation.
Is this statement wrong?
If MyClass owns an IDisposable resource, then MyClass should itself be IDisposable, and it should dispose the encapsulated resource when Dispose() is called on MyClass:
public class MyClass : IDisposable {
// ...
public virtual void Dispose() {
if(stream != null) {
stream.Dispose();
stream = null;
}
if(log != null) {
log.Dispose();
log = null;
}
}
}
No, you should not implement a finalizer here.
Note: an alternative implemention might be something like:
private static void Dispose<T>(ref T obj) where T : class, IDisposable {
if(obj != null) {
try { obj.Dispose(); } catch {}
obj = null;
}
}
public virtual void Dispose() {
Dispose(ref stream);
Dispose(ref log);
}
For objects containing other IDisposable objects, it's a good and recommended practice to implement IDisposable on your own object, so others consuming your type can wrap it in a using statement:
public class MyClass : IDisposable
{
public MyClass()
{
log = new EventLog { Source = "MyLogSource", Log="MyLog" };
FileStream stream = File.Open("MyFile.txt", FileMode.OpenOrCreate);
}
private readonly EventLog log;
private readonly FileStream stream;
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free managed objects here
stream.Dispose();
}
}
// Other members, using the fields above
}
In your case, you aren't freeing up any managed resources so no finalizer is needed. If you were, then you would implement a finalizer and call Dispose(false), indicating to your dispose method that it is running from the finalizer thread.
If you don't implement IDisposable, you're leaving it up to the GC to clean up the resources (e.g, close the Handle on the FileStream you've opened) once it kicks in for collection. Lets say your MyClass object is eligible for collection and is currently in generation 1. You would be leaving your FileStream handle open until the GC cleans up the resource once it runs. Also, many implementations of Dispose call GC.SuppressFinalize to avoid having your object live another GC cycle, passing from the Initialization Queue to the F-Reachable queue.
Much of the advice surrounding Dispose and Finalize was written by people who expected Finalize to be workable as a primary resource cleanup mechanism. Experience has shown such expectation to have been overly optimistic. Public-facing objects which acquire any sort of resources and hold them between method calls should implement IDisposable and should not override Finalize. If an object holds any resources which would not otherwise get cleaned up if it was abandoned, it should encapsulate each such resource in a privately-held object which should then use Finalize to clean up that resource if required.
Note that a class should generally not use Finalize to clean up resources held by other objects. If Finalize runs on an object that holds a reference to the other object, one of several conditions will usually apply:
No other reference exists to the other object, and it has already run Finalize, so this object doesn't need to do anything to clean it up.
No other reference exists to the other object, and it hasn't yet run Finalize but is scheduled to do so, so this object doesn't need to do anything to clean it up.
Something else is still using the other object, so this object shouldn't try to clean it up.
The other object's clean-up method cannot be safely run from within the context of a finalizer thread, so this object shouldn't try to clean it up.
This object only became eligible to run Finalize because all necessary cleanup has already been accomplished, so this object doesn't need to do anything to clean things up.
Only define a Finalize method in those cases where one can understand why none of the above conditions apply. Although such cases exist, they are rare, and it's better not to have a Finalize method than to have an inappropriate one.
In .NET (C#) I follow some custom conventions and patterns that require Constructors, Initialization functions and IDisposable implementations. A typical class is illustrated below. No initialization is done directly in the constructor but rather through a dedicated function that is supposed to make the object reusable. However, I am not sure what happens when Dispose gets called. If the GC calls it, the reference to the object is lost anyways so no worries there. If it is explicitly called, are there any drawbacks simply calling Initialize and treating the class as a fresh object since GC.SupressFinalize has been called? Lol, I'm sure I could have asked this in an easier way.
public abstract class Thread: System.IDisposable
{
protected bool Disposed { get; set; }
protected bool Terminate { get; private set; }
public bool IsRunning { get; private set; }
private System.Threading.Thread ThreadObject { get; set; }
public Thread ()
{
this.Initialize();
}
~Thread ()
{
this.Dispose(false);
}
public virtual void Initialize ()
{
this.Stop();
this.Disposed = false;
this.Terminate = true;
this.IsRunning = false;
this.ThreadObject = null;
}
//====================================================================================================
// Functions: Thread
//====================================================================================================
public void Start ()
{
if (!this.IsRunning)
{
this.IsRunning = true;
this.Terminate = false;
this.ThreadObject = new System.Threading.Thread(new System.Threading.ThreadStart(this.Process));
this.ThreadObject.Start();
}
}
/// <summary>
/// Override this method to do thread processing.
/// [this.Terminate] will be set to indicate that Stop has been called.
/// </summary>
/// <param name="template"></param>
protected abstract void Process ();
public void Stop (System.TimeSpan timeout)
{
if (this.IsRunning)
{
this.Terminate = true;
try
{
if (timeout.TotalMilliseconds > 1D)
{
this.ThreadObject.Join(timeout);
}
else
{
this.ThreadObject.Join();
}
}
catch
{
try
{
this.ThreadObject.Abort();
}
catch
{
}
}
this.ThreadObject = null;
this.IsRunning = false;
}
}
//====================================================================================================
// Interface Implementation: System.IDisposable
//====================================================================================================
public void Dispose ()
{
this.Dispose(true);
System.GC.SuppressFinalize(this);
}
protected virtual void Dispose (bool disposing)
{
if (!this.Disposed)
{
if (disposing)
{
// Dispose managed resources.
this.Stop(System.TimeSpan.FromSeconds(1));
}
// Dispose unmanaged resources here.
// Note disposing has been done.
this.Disposed = true;
}
}
}
The GC never calls Dispose, it's up to the consuming code. The GC does however call the finalizer. This is used in the best practice IDisposable implementation to clean up unmanaged code only.
Where Dispose is used outside of the context of a finalizer, then there is no need for the GC to call the finalizer, and therefore SuppressFinalize is used as an optimisation to prevent it happening twice.
If the object is reused this causes an issue. Technically you can re-register the finalizer on initialization, but this would need to be made thread safe. Common practice is that an object is not reused after it has been Disposed, and typically the Dispose method should only execute exactly once. IMO the initializer method and object reuse introduces complexities to the pattern that move it away from it's intended purpose.
There's no technical reason why you can't reactivate a disposed object in this way, though I woudln't do it as it's against the principle of least surprise (most disposable objects are used once).
If you really do want to go this way, I'd avoid having a finalizer, which means your IDisposable class must not directly own any unmanaged resources. You can do this by wrapping any unmanaged resources your class uses in a manged wrapper (e.g. look at the SafeHandle class for an example).
I don't like all the precise details of your thread handling, but if you are going to have a class where each instance owns a thread, you should provide a Dispose method which will ensure that the instance's thread dies off in an orderly fashion.
If you want to allow for the thread to get cleaned up even when an object is abandoned, you'll probably have to create a wrapper object to which the outside application holds a reference but your thread does not. The Finalize() method for that wrapper object should nudge the thread in such a way that it will die off. The thread could simply poll a flag every few seconds to see if it should exit, or there could be a more sophisticated termination strategy.
I'm confused, though, why Initialize calls Stop()? I would have expected it to call Start().
Wrong language pattern appication sample is used in the code. I clearly see C++ backgroung for the C# code author. Unfortunately C++ coding techniques in not applicable in C# language.
Better not to allow object to get into garbage collector (GC), simply referencing it somewhere else, as in the Singleton pattern, rather that trying to resurrect disposed object, or use Dispose pattern in a language not allowing full control for the garbage collector and memory management, as is to be true, for example, in C++.
Simply, you should not use C++ idioms in C#, but the tips and tricks are:
Interfaces instead of pure virtual functions in C++,
Interface inheritancee instead of multiple class inheritance in C++,
No memory management (use weak references) instead of full controlled object lifetime in C++
My question is why do I need IDisposable? I have a class that consumes some resources
that need to be freed. I have two options
Without IDisposable
class SomeUtilityClass
{
public Stop()
{
// free resources
}
}
With IDisposable
class SomeUtilityClass, IDisposable
{
public void Dispose()
{
// free resources
}
}
So why do I need IDisposable here? It does not matther how to name the function.
class Program
{
public Main(..)
{
SomeUtilityClass _class = new SomeUtilityClass();
// clean up when we've done
_class.Stop();
// OR
_class.Dispose();
}
}
Because IDisposable is supported by C# and you can use cool using syntax:
using (IDisposable someDisposable = new ...)
{
// your code with someDisposable
}
This is actually transformed by compiler to something like:
IDisposable someDisposable = new ...
IDisposable someDisposable2 = someDisposable ;
try
{
// your code with someDisposable
}
finally
{
if (someDisposable2 != null)
{
someDisposable2.Dispose();
}
}
So if any exception happens inside using block your object would be disposed anyway.
You should only really use IDisposable when your class consumes unmanaged resources, and they need to be freed immediately (streams, db etc).
It also provides a way for the CLR to 'clean up' when there are unhandled exceptions that cause your thread to be unloaded.
Calling IDisposable marks the object as being available for garbage collection immediately, but if not implemented correctly you can cause your object to be promoted a garbage collection generation which can cause memory pressure (refer to Jeffery Richters CLR via c# 3 if you want a full explanation).
a quick google turned this up:
http://kleahy-technical.blogspot.com/2009/01/idisposable-and-garbage-collection.html
i suggest you read into the IDisposable pattern, when to use it, when not to and its implications on GC and state.
EDIT:
there is loads of info on stackoverflow too:
Use of Garbage Collection?
Well in your case, there is not much point implementing IDisposable, since you can manually dispose of your resources.
A common use of IDisposable is when you expose an interface that handles data connections, and you want all derived classes to dispose when they're done.
Consider this:
public interface IDataCtx
{
void CallDB();
}
public class MyDataCtx : IDataCtx
{
private SqlConnection dc;
public MyDataCtx() { dc = new SqlConnection(); dc.Open(); }
public void CallDB();
{
dc.Something();
}
}
Allowing you to do something like this:
IDataCtx ctx = new MyDataCtx();
ctx.CallDB();
But wait, what about that open connection? Uh oh!
If you made IDataCtx : IDisposable (and implemented the code in your derived ctx), you could do this:
IDataCtx ctx;
using (ctx = new MyDataCtx())
{
ctx.CallDB();
}
Guaranteeing that whatever implementation of IDataCtx you use, it will always be disposed of (even in the case of an exception).
That's how i use it anyway. (plus it's just good practice).
IDisposable interacts with the using keyword to make it easy to clean up after yourself, e.g.:
using (var file = new FileStream(...))
{
file.Write(...);
}
In the above code, the FileStream is closed as soon as the using block completes, rather than waiting around to be garbage-collected.
It's a convention used in the C# language.
You also get the nifty using statement to your disposal.
using (SomeUtilityClass _class = new SomeUtilityClass()) {
} // Dispose is automatically called
As well as being able to use the using statement, it also give the garbage collector a hint that the object can be removed from memory.
If your class owns unmanaged resources or your class owns managed IDisposable resources you should in generel implement the IDisposable interface.
An easy readable little article on when to implement IDisposable and Finalizers can be found here: http://nitoprograms.blogspot.com/2009/08/how-to-implement-idisposable-and.html
I have a class that makes use of temporary files (Path.GetTempFileName()) while it is active. I want to make sure these files do not remain on the user's hard drive taking up space after my program is closed. Right now my class has a Close() method which checks if any temporary files used by the class still exist and deletes them.
Would it make more sense to put this code in the Dispose() or Finalize() methods instead?
Better yet would be to create the file with FileOptions.DeleteOnClose. This will ensure that the operating system forcibly deletes the file when your process exits (even in the case of a rude abort). Of course, you will still want to close/delete the file yourself when you are done with it, but this provides a nice backstop to ensure that you don't allow the files to be sit around forever
Example:
using (FileStream fs = File.Create(Path.GetTempFileName(), Int16.MaxValue,
FileOptions.DeleteOnClose))
{
// Use temp file
} // The file will be deleted here
I would do both; make the class disposable, and have the finalizer clean it up. There is a standard pattern for doing so safely and effectively: use it rather than attempting to deduce for yourself what the right pattern is. It is very easy to get wrong. Read this carefully:
http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
Note that you've got to be really really careful when writing a finalizer. When the finalizer runs, many of your normal assumptions are wrong:
There are all kinds of potentials for race conditions or deadlocks because you are no longer on the main thread, you're on the finalizer thread.
In regular code, if you're running code inside an object then you know that all the things the object refers to are alive. In a finalizer, all the things the object refers to might have just been finalized! Finalizers of dead objects can run in any order, including "child" objects being finalized before "parent" objects.
In regular code, assigning a reference to an object to a static field could be perfectly sensible. In a finalizer, the reference you are assigning could be to an already dead object, and therefore the assignment brings a dead object back to life. (Because objects referred to by static fields are always alive.) That is an exceedingly weird state to be in and nothing pleasant happens if you do.
And so on. Be careful. You are expected to fully understand the operation of the garbage collector if you write a non-trivial finalizer.
A file is an unmanaged resource, and you implement IDisposable to clean up unmanaged resources that your classes are dependent upon.
I have implemented similar classes, although never in production code.
However, I understand your tentativeness about this - user interaction with the files outside of your application could screw things up and cause problems during disposal. However, that is the same for any file created/deleted by an application, regardless of whether or not it's tidied up by a Dispose() method or not.
I'd have to say that implementing IDisposable would be a reasonable choice.
A nice way is suggested by David M. Kean on the MSDN entry on Path.GetTempFileName. He creates a wrapper class implementing IDisposable that will automatically remove the file:
public class TemporaryFile : IDisposable
{
private bool _isDisposed;
public bool Keep { get; set; }
public string Path { get; private set; }
public TemporaryFile() : this(false)
{
}
public TemporaryFile(bool shortLived)
{
this.Path = CreateTemporaryFile(shortLived);
}
~TemporaryFile()
{
Dispose(false);
}
public void Dispose()
{
Dispose(false);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
_isDisposed = true;
if (!this.Keep)
{
TryDelete();
}
}
}
private void TryDelete()
{
try
{
File.Delete(this.Path);
}
catch (IOException)
{
}
catch (UnauthorizedAccessException)
{
}
}
public static string CreateTemporaryFile(bool shortLived)
{
string temporaryFile = System.IO.Path.GetTempFileName();
if (shortLived)
{
// Set the temporary attribute, meaning the file will live
// in memory and will not be written to disk
//
File.SetAttributes(temporaryFile,
File.GetAttributes(temporaryFile) | FileAttributes.Temporary);
}
return temporaryFile;
}
}
Using the new class is easy, just type the following:
using (TemporaryFile temporaryFile = new TemporaryFile())
{
// Use temporary file
}
If you decide, after constructing a TemporaryFile, that you want to prevent it from being deleted, simply set the TemporaryFile.Keep property to true:
using (TemporaryFile temporaryFile = new TemporaryFile())
{
temporaryFile.Keep = true;
}
Absolutely. This way you can ensure cleanup with exceptions present.
You should definitely use Dispose to clean up resources, but make sure you implement the IDisposable interface. You don't want to just add a method named Dispose.
I always make my classes that point to temp files IDisposable, and usually implement a finalizer that calls my dispose method there as well. This seems to be the paradigm suggested by the IDisposable MSDN page.
Related code below:
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
// Note disposing has been done.
disposed = true;
}
}
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
If you wish to re-use your temporary files e.g. open\close\read\write\etc, then clearing them up at the AppDomain unload level can be useful.
This can be used in combination with putting temp files in a well known sub-directory of a temp location and making sure that the directory is deleted on application startup to ensure unclean shut-downs are taken care of.
A basic example of the technique (with exception handling removed around delete for brevity). I use this technique in file-based unit tests where it makes sense and is useful.
public static class TempFileManager
{
private static readonly List<FileInfo> TempFiles = new List<FileInfo>();
private static readonly object SyncObj = new object();
static TempFileManager()
{
AppDomain.CurrentDomain.DomainUnload += CurrentDomainDomainUnload;
}
private static void CurrentDomainDomainUnload(object sender, EventArgs e)
{
TempFiles.FindAll(file => File.Exists(file.FullName)).ForEach(file => file.Delete());
}
public static FileInfo CreateTempFile(bool autoDelete)
{
FileInfo tempFile = new FileInfo(Path.GetTempFileName());
if (autoDelete)
{
lock (SyncObj)
{
TempFiles.Add(tempFile);
}
}
return tempFile;
}
}
Does the following code render the using(...) function/purpose irrelevant?
Would it cause a deficiency in GC performance?
class Program
{
static Dictionary<string , DisposableClass> Disposables
{
get
{
if (disposables == null)
disposables = new Dictionary<string , DisposableClass>();
return disposables;
}
}
static Dictionary<string , DisposableClass> disposables;
static void Main(string[] args)
{
DisposableClass disposable;
using (disposable = new DisposableClass())
{
// do some work
disposable.Name = "SuperDisposable";
Disposables["uniqueID" + Disposables.Count] = disposable;
}
Console.WriteLine("Output: " + Disposables["uniqueID0"].Name);
Console.ReadLine();
}
}
class DisposableClass : IDisposable
{
internal string Name
{
get { return myName; }
set { myName = value; }
}
private string myName;
public void Dispose( )
{
//throw new NotImplementedException();
}
}
Output: SuperDisposable
My understanding of the using(...) function is to immediately coerce disposal of the DisposableClass. Yet within the code block, we are adding the class to a dictionary collection. My understanding is that a class is inherently a reference type. So my experiment was to see what would happen to the disposable object added to a collection in this manner.
In this case DisposableClass is still quite alive. Classes are a reference type - so my assumption then became that the collection is not simply referencing this type, but indeed holding the class as a value. But, that didn't make sense either.
So what is really going on?
EDIT: modified code with output to prove that the object is not dead, as might be suggested by some answers.
2nd EDIT: what this comes down to as I've gone through some more code is this:
public void Dispose( )
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool dispose)
{
if (!isDisposed)
{
if (dispose)
{
// clean up managed objects
}
// clean up unmanaged objects
isDisposed = true;
}
}
~DisposableClass( )
{ Dispose(false); }
Stepping through the code (had a breakpoint at private void Dispose(bool dispose)), where false is passed to the method, it becomes imperative that resources are properly disposed of here. Regardless, the class is still alive, but you are definitely setting yourself up for exceptions. Answers made me more curious...
Disposing an object does not destroy it; it simply tells it to clean up any unmanaged resources it uses as they are no longer needed. In your example, you're creating a disposable object, assigning to a dictionary, and then just telling it to remove some resources.
The correct scenario for the using statement is when you want to initialize a resource, do something with it, and then destroy it and forget about it; for example:
using (var stream = new FileStream("some-file.txt"))
using (var reader = new StreamReader(stream))
{
Console.Write(reader.ReadToEnd());
}
If you want to retain the object after you've used it, you shouldn't be disposing it, and hence a using statement should not be used.
You should not be using a using block in this case, since you need the object after the block has finished. It is only to be used when there is a clear starting and ending point of the lifetime of the object.
It's important to remember that IDisposable, while a slightly special interface, is an interface nonetheless. When the using block exits, it calls Dispose() on your object. Nothing more. Your reference is still valid and, if your Dispose method does nothing, your object will be completely unaffected. If you don't keep track the disposal and explicitly throw exceptions, then you won't get any exceptions after that point because there is no inherent disposed state in .NET.
The IDisposable interface indicates that a type manages some kind of resource. The Dispose method exists to allow you to dispose of the resources used by an instance without having to wait for garbage-collection to take place and the resources to be freed by a finalizer.
In your example, the dictionary is still containing a reference to the disposable class, but the instance will have been disposed at the end of the using block. Subsequent attempts to call methods on the instance will now likely throw ObjectDisposedException or InvalidOperationException, to indicate the instance is no longer in a "working" state.
Disposing an IDisposable is not to be confused with releasing the memory occupied the instance, or invoking any garbage-collection routines on it. The instance is tracked and managed by the garbage-collector like any other, only to be released when the garbage-collector decides it.