I have a stack of WindowsImpersonationContext objects, which are IDisposable type. Now consider these two operations:
Stack<WindowsImpersonationContext> stack = new Stack<WindowsImpersonationContext>();
public void BeginOperation()
{
// Push object to stack
var context = WindowsIdentity.Impersonate(...);
stack.Push(context);
}
public void EndOperation()
{
// Pop object from stack.
if (stack.Count != 0)
{
var context = stack.Pop();
... do various stuff with 'context' ...
context.Dispose(); // should this be called once the object is not needed anymore?
}
}
Should I call Dispose() manually if I don't want to wait for the GC to do it? Is it safe to do it like this if I'm 100% no other code will try to use the context object referenced in the stack? To be precise, if I don't explicitly call context.Dispose(), I assume that even after the execution returns from EndOperation(), I'm at the mercy of GC in regard to disposing resources occupied by the 'context' object, despite it not being referenced by the stack anymore? Is my reasoning correct?
Also, using the above code, is it correct to claim that after executing the following set of operations, the stack will end up empty in terms of resources occupied (i.e. all objects it used to contain are disposed at the end, and I don't need to worry about disposing anything elsewhere anymore):
BeginOperation();
BeginOperation();
EndOperation();
EndOperation();
EDIT: I realise that using can/should be used for safety purposes, but mainly I'm concerned with what's going on in the background in terms of collections/GC, regardless of the syntax ...
If you don't need it anymore and it implements IDisposable use the using-statement.
public void EndOperation()
{
// Pop object from stack.
if (stack.Count != 0)
{
using(var context = stack.Pop())
{
// ... do various stuff with 'context' ...
}
}
}
Apart from that Stack.Pop is implemented in this way(ILSPy, .NET 4):
// System.Collections.Stack
public virtual object Pop()
{
if (this._size == 0)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyStack"));
}
this._version++;
object result = this._array[--this._size];
this._array[this._size] = null;
return result;
}
So you see that there's no reference anymore in the stack after Pop.
In general you should use using (or try-finally) whenever you use unmanaged resources. On this way it is ensured that they are disposed even on error.
If you are sure that nothing other than the stack had a reference to the object in question, then yes: You should dispose it yourself manually.
I'd change your code to look more like this:
public void EndOperation()
{
// Pop object from stack.
if (stack.Count != 0)
{
using (var context = stack.Pop())
{
... do various stuff with 'context' ...
}
}
}
That way it will be disposed even if an exception occurs in the "do various stuff" block.
If you don't dispose it yourself, then you rely on a finalizer being implemented for the class being disposed - and even if a finalizer is implemented, it may be called too late (imagine if it was an open file handle).
You can use using statement but before you should implements IDisposable.
Related
Yesterday, after running Visual Studio code analysis on our codebase, the following code was highlighted as an issue:
using (var stringReader = new StringReader(someString))
{
using (var reader = XmlReader.Create(stringReader)) {
// Code
}
}
The warning that was returned was
Warning CA2202 Object 'stringReader' can be disposed more than once in
method '(method name)'. To avoid generating a
System.ObjectDisposedException you should not call Dispose more than
one time on an object.
After searching stack overflow, I've come to the general understanding that if I were to create a custom class containing IDisposable members, it should implement IDisposable itself, and call the dispose() method of the member.
My two questions are
In all cases where object X takes a reference to an IDisposable object Y as a parameter during creation, is it correct to assume that the object X will take ownership of Y and from that point onwards, calling X.dispose() will always result in calling Y.dispose()
This is an old piece of code and exceptions as described in the warning message have never been reported (to the best of my knowledge). If the above point is assumed, why does the double using block not result in calling stringReader.dispose() twice and therefore throwing an exception?
is it correct to assume that the object X will take ownership of Y and from that point onwards, calling X.dispose() will always result in calling Y.dispose()
No, it is never save to assume that. Let's check this specific case: XmlReader.Create(Stream).
After going to quite some code in the Reference Source, I have found that the Dispose method calls the Close method. That is quite obvious. Then notice this piece of code:
public override void Close() {
Close( closeInput );
}
So whether the backing stream will be closed and disposed depends on the value of the setting closeInput, which you can set through the XmlReaderSettings.CloseInput setting.
So the answer here is a definite no: you can't be sure it is disposed. You should always make sure yourself it is.
No, you cannot assume that another object will call Dispose() while disposing itself. The object having the disposable object as a reference might not even be using the disposable resource.
This warning is known to be somewhat weird. Look here to see some complaints about the warning. You should design your class so that it must be safe to call Dispose() more than once.
By the way, MSDN says:
A method implementation contains code paths that could cause multiple calls to IDisposable.Dispose or a Dispose equivalent, such as a Close() method on some types, on the same object.
So a path to the Close() method call can generate this warning too, which is why you see this warning in your case.
In all cases where object X takes a reference to an IDisposable object Y as a parameter during creation, is it correct to assume that the object X will take ownership of Y and from that point onwards, calling X.dispose() will always result in calling Y.dispose()
I think not and I will try to explain why.
There is a pattern called IDisposablePattern which looks something like that:
public class SimpleClass : IDisposable
{
// managed resources SqlConnection implements IDisposable as well.
private SqlConnection _connection;
private bool _disposed;
// implementing IDisposable
public void Dispose()
{
// Here in original Dispose method we call protected method with parameter true,
// saying that this object is being disposed.
this.Dispose(true);
// Then we "tell" garbage collector to suppress finalizer for this object because we are releasing
// its memory and doesnt need to be finalized. Calling finalizer(destructor) of a given type is expensive
// and tweaks like this help us improve performance of the application.
GC.SuppressFinalize(this);
}
// Following the best practices we should create another method in the class
// with parameter saying whether or not the object is being disposed.
// Its really important that this method DOES NOT throw exceptions thus allowing to be called multiple times
protected virtual void Dispose(bool disposing)
{
// another thing we may add is flag that tells us if object is disposed already
// and use it here
if (_disposed) { return; }
if (_connection != null)
{
_connection.Dispose();
_connection = null;
}
_disposed = true;
// call base Dispose(flag) method if we are using hierarchy.
}
}
Note that this can be extended to new level when your class uses unmanaged resources like this one:
public class SimpleClass2: IDisposable
{
// managed resources
private SqlConnection _connection;
private bool _disposed;
// unmanaged resources
private IntPtr _unmanagedResources;
// simple method for the demo
public string GetDate()
{
// One good practice that .NET Framework implies is that when object is being disposed
// trying to work with its resources should throw ObjectDisposedException so..
if(_disposed) { throw new ObjectDisposedException(this.GetType().Name);}
if (_connection == null)
{
_connection = new SqlConnection("Server=.\\SQLEXPRESS;Database=master;Integrated Security=SSPI;App=IDisposablePattern");
_connection.Open();
}
// allocation of unmanaged resources for the sake of demo.
if (_unmanagedResources == IntPtr.Zero)
{
_unmanagedResources = Marshal.AllocHGlobal(100 * 1024 * 1024);
}
using (var command = _connection.CreateCommand())
{
command.CommandText = "SELECT getdate()";
return command.ExecuteScalar().ToString();
}
}
public void Dispose()
{
// Here in original Dispose method we call protected method with parameter true,
// saying that this object is being disposed.
this.Dispose(true);
// Then we "tell" garbage collector to suppress finalizer for this object because we are releasing
// its memory and doesnt need to be finalized. Calling finalizer(destructor) of a given type is expensive
// and tweaks like this help us improve performance of the application.
// This is only when your class doesnt have unmanaged resources!!!
// Since this is just made to be a demo I will leave it there, but this contradicts with our defined finalizer.
GC.SuppressFinalize(this);
}
// Following the best practices we should create another method in the class
// with parameter saying wether or not the object is being disposed.
// Its really important that this method DOES NOT throw exceptions thus allowing to be called multiple times
protected virtual void Dispose(bool disposing)
{
// another thing we may add is flag that tells us if object is disposed already
// and use it here
if (_disposed) { return; }
// Thus Dispose method CAN NOT release UNMANAGED resources such as IntPtr structure,
// flag is also helping us know whether we are disposing managed or unmanaged resources
if (disposing)
{
if (_connection != null)
{
_connection.Dispose();
_connection = null;
}
_disposed = true;
}
// Why do we need to do that?
// If consumer of this class forgets to call its Dispose method ( simply by not using the object in "using" statement
// Nevertheless garbage collector will fire eventually and it will invoke Dispose method whats the problem with that is if we didn't
// have the following code unmanaged resources wouldnt be disposed , because as we know GC cant release unmanaged code.
// So thats why we need destructor(finalizer).
if (_unmanagedResources != IntPtr.Zero)
{
Marshal.FreeHGlobal(_unmanagedResources);
_unmanagedResources = IntPtr.Zero;;
}
// call base Dispose(flag) method if we are using hierarchy.
}
~DatabaseStateImpr()
{
// At this point GC called our finalizer method , meaning
// that we don't know what state our managed resources are (collected or not) because
// our consumer may not used our object properly(not in using statement) so thats why
// we skip unmanaged resources as they may have been finalized themselves and we cant guarantee that we can
// access them - Remember? No exceptions in Dispose methods.
Dispose(false);
}
}
I have a question about the following code:
DisposableObject holdon = null;
using (DisposableObject o = new DisposableObject())
{
Console.WriteLine("Inside using block");
holdon = o;
}
holdon.Method();
When I ran this code, I expected to get an exception on the line holdon.Method(), but to my surprise, It happily called Method() without any problem. I was able to confirm that DisposableObject.Dispose() is being called on o upon hitting the end of the using block. This raises a question that I didn't have a lot of luck finding the answer to on MSDN. After the using block, holdon is definitely still pointing to a valid object in memory despite the fact that Dispose() was called. So does holdon still point to the same object previously pointed to by o, or does it point to a copy of o?
Disposing object is not related to removing object from memory. It only means calling Dispose() method on that object. All further actions depend on IDisposable implementation of the object you have disposed. In some cases object is set to 'disposed' state and all further actions raise an exception (ObjectDisposedException). But you are free to do anything (or not do) when you implement IDisposable.
E.g. this is a totally valid IDisposable implementation (fiddle):
public class CrazyDisposable : IDisposable
{
public int Counter { get; private set; }
public void Dispose() => Counter++;
}
Further reading: using statement (C# Reference).
And particularly part which explains why it's better to limit the scope of the disposable object to the using block:
You can instantiate the resource object and then pass the variable to
the using statement, but this is not a best practice. In this case,
the object remains in scope after control leaves the using block even
though it will probably no longer have access to its unmanaged
resources. In other words, it will no longer be fully initialized. If
you try to use the object outside the using block, you risk causing an
exception to be thrown. For this reason, it is generally better to
instantiate the object in the using statement and limit its scope to
the using block.
as you can see - it's allowed, but you risk when you access the disposed object.
the using statement is just shorthand for
DisposableObject holdon = null;
{ //This "{" is here to limit the scope of "o"
DisposableObject o = new DisposableObject()
try
{
Console.WriteLine("Inside using block");
holdon = o;
}
finally
{
if(o != null)
o.Dispose();
}
}
holdon.Method();
So if calling
o.Dispose();
o.Method();
in normal code does not cause a exception then calling holdon.Method() after o.Dispose() will not cause a exception either.
I noticed the following object disposal code pattern in a C# project and I was wondering if it's acceptable (although it works).
public object GetData()
{
object obj;
try
{
obj = new Object();
// code to populate SortedList
return obj;
}
catch
{
return null;
}
finally
{
if (obj != null)
{
obj.Dispose();
obj = null;
}
}
}
For this example, I'm using a general 'object' instead of the actual IDisposable class in the project.
I know that the 'finally' block will be executed every time, even when the value is returned, but would it affect the return value (or would it be a new object instance) in any way since the object is being set to null (for what seems like object disposal and GC purposes).
Update 1:
I tried the following snippet and the return object is non-null, although the local object is set to null, so it works, which is a bit strange considering some of the comments below:
public StringBuilder TestDate()
{
StringBuilder sb;
try
{
sb = new StringBuilder();
sb.Append(DateTime.UtcNow.ToString());
return sb;
}
catch
{
return null;
}
finally
{
sb = null;
}
}
Btw, I'm using C# 4.0.
P.S. I'm just reviewing this project code. I'm not the original author.
Update 2:
Found the answer to this mystery [1]. The finally statement is executed, but the return value isn't affected (if set/reset in the finally block).
[1] What really happens in a try { return x; } finally { x = null; } statement?
This code will compile fine (assuming that you are not actually using an Object but something that implements IDisposable), but it probably won't do what you want it to do. In C#, you don't get a new object without a new; this code will return a reference to an object that has already been disposed, and depending on the object and what Dispose() actually does, trying to use a disposed object may or may not crash your program.
I assume the idea is to create an object, do some stuff with it, then return the object if successful or null (and dispose the object) on failure. If so, what you should do is:
try {
obj = new MyClass();
// ... do some stuff with obj
return obj;
}
catch {
if(obj != null) obj.Dispose();
return null;
}
Simply using the using statement achieves the same result as that, and is the standard practice
public int A()
{
using(IDisposable obj = new MyClass())
{
//...
return something;
}
}
I would, however, advise against returning your IDisposable object.
When you dispose of an object, it is supposed to be considered "unusable". And so, why return it?
If the object's lifetime needs to be longer than the method A's lifetime, consider having the calling method B instantiate the object, and pass it as a parameter to method A.
In this case, method Bwould be the one using the using statement, inside which it would call A.
If you are returning an IDisposable object, then it is the responsibility of your caller to dispose of it:
public IDisposable MakeDisposableObject()
{
return new SqlConnection(""); // or whatever
}
caller:
using (var obj = MakeDisposableObject())
{
}
It makes less than no sense for your method to dispose of an object and then return it. The disposed object will be of no value to the caller. In general, referencing a disposable object which has been disposed should produce an ObjectDisposedException.
A few observations.
That code wouldn't compile because object doesn't have a .Dispose() method.
Why wouldn't you use IDisposable?
Why would you dispose of an object that is being returned, since returning you would return an object for the purpose of some other code to use it. The concept of "disposing" of something is to give it a chance to clean up after itself and its used, un-managed resources. If you are returning an object that is supposed to be used elsewhere, but has unmanaged resources that you want to clean up before the object gets used anywhere else, then you shuld really have 2 separate objects. One to load some data that would be disposable, and another object that would contain the usable loaded content that you want to pass around. An example of this would be something like stream readers in the .NET framework. You would normally new a stream reader, read it into a byte[] or some other data object, .Dispose() the stream reader, then return the byte[]. The "loader" that has some resources to dispose of in a timely fashion is separate from the object containing the "loaded" data that can be used without needing to be disposed.
Please see the code below. I expect it to print either 10 because I have explicitly invoked the garbage collector. But I always get either a 0 or 20 as output. Why is that?
void Main()
{
Panda[] forest_panda = new Panda[10];
for(int i=0; i<forest_panda.GetLength(0);i++)
{
forest_panda[i]=new Panda("P1");
}
for(int i=0; i<forest_panda.GetLength(0);i++)
{
forest_panda[i]=new Panda("P1");
}
System.GC.Collect();
Console.WriteLine("Total Pandas created is {0}",Panda.population);
}
class Panda
{
public static int population=0;
public string name;
public Panda(string name)
{
this.name = name;
population = population + 1;
}
~Panda()
{
population = population - 1;
}
}
Please note that the class for Main is automatically created by LINQPad (the editor that comes with the "C# 4.0 in a Nutshell" book). I am new to C#.
You have not run an explict garbage collection. From the docs of GC.Collect():
Use this method to attempt to reclaim
all memory that is inaccessible.
However, the Collect method does not
guarantee that all inaccessible memory
is reclaimed.
All objects, regardless of how long
they have been in memory, are
considered for collection; however,
objects that are referenced in managed
code are not collected. Use this
method to force the system to attempt
to reclaim the maximum amount of
available memory.
The garabage collector is highly optimized and "decides" all by himself when he actually does the garbage collection and then call the finalizers. Additionally it is all done asynchronously. That is also why Finalizers are called non-deterministic cleanup. You never now when cleanup happens.
You have two options now. You can either call GC.WaitForPendingFinalizers() wich will halt the current thread until the all finalizable objects have been finalized. Or call this new overload: System.GC.Collect(int generation, System.GCCollectionMode mode) with GCCollectionMode.Forced It was introduced in .NET 3.5.
Just keep in mind that usually it is not necessary and more importantly: a bad idea to call the garbage collector manually. Also implementing the finalizer is only needed in rare occasions. Calling the garbage collector will slow down the runtime. Implementing finalizers will slow down the runtime additionally. The garabge collector puts all objects that implement the finalizer into the finalization queue when they are ready to be garabge collected. Processing this queue is expensive.
To make things worse, when the finalizer is run, it is not guaranteed that the members you are trying to access there are still alive. It is very well possible they have already been grabage collected. That's why you should use the finalizer only when you have unmanaged resources that need to be cleaned up.
All this is definately not needed in your example. What you acutally want is IDisposable for deterministic cleanup.
There are a couple of things to notice here:
First of all the GC behaves differently between release and debug builds. Generally, in release mode objects can be reclaimed sooner than in debug mode.
As Tim points out calling GC.Collect doesn't call finalizers. If you want to wait for finalizers to run call GC.WaitForPendingFinalizers as well.
Finalizers are run by a dedicated thread, so you're actually modifying state from two different threads without any synchronization. While this may not be a problem in this particular case, doing so is not a good idea. But before you go and add synchronization to your finalizer, please keep in mind that a deadlocked finalizer means that no more finalizers will run and thus the memory for those objects will not be reclaimed.
Try adding System.GC.WaitForPendingFinalizers after you garbage collect.
http://www.developer.com/net/csharp/article.php/3343191/C-Tip-Forcing-Garbage-Collection-in-NET.htm
You create twenty objects, so the value would then be 20. Explicitly calling System.GC.Collect() does not actually guarantee calling the destructor. Therefore if it was called all 20 objects may have been destructed or none may have been.
This explains what is actually happening.
It isn't good practice to create a destructor or call GC.Collect explicitly.
If An object needs to do cleanup, it should implement IDisposable
In .NET, object lifetimes are non-deterministic and do not behave as you'd expect from C++ constructor/destructors. In fact, .NET objects do not technically have destructors. The finalizer differs in that it is expected to clean up unmanaged resources used by the object during it's lifetime.
To have a deterministic way of freeing resources used by your object, you implement the IDisposable interface. IDisposable isn't perfect though as it still requires the calling code to correctly dispose of the object when it's done, and it's hard to handle accidental multiple calls to Dispose. However syntax in C# makes this generally very easy.
class Panda : IDisposable
{
public static int population = 0;
public string _name;
public Panda( string name )
{
if( name == null )
throw new ArgumentNullException( name );
_name = name;
population++;
}
protected virtual void Dispose( bool disposing )
{
if( disposing && name != null )
{
population--;
name = null;
}
}
public void Dispose()
{
Dispose( true );
GC.SuppressFinalize( this );
}
~Panda(){ Dispose( false ); }
}
Then to use the class:
using( var panda = new Panda( "Cute & Cuddly" ) )
{
// Do something with the panda
} // panda.Dispose() called automatically
Using destructors (a.k.a. finalizers) is not really a good way of doing things in C#. There is no guarantee that the finalizer will ever run, even if you explicitly invoke the garbage collector. You shouldn't try to force garbage collection either, because it will probably have a negative perfomance impact on your application overall.
Instead, if you need to explicitly free resources owned by an object, you should implement the IDisposable interface, and place your cleanup logic inside the Dispose() method. Conversely, when you use an object that implements IDisposable, you should always take care to call its Dispose() method when you are finished with it. C# provides the "using" statement for this purpose.
Many classes that do I/O (such as Streams) implement IDisposable. Here is an example of using a FileStream to read a text file. Note the "using" statement to ensure the FileStream is disposed when we are finished with it:
using (FileStream fs = File.OpenRead("C:\\temp\\myfile.txt"))
{
// Read a text file 1024 bytes at a time and write it to the console
byte[] b = new byte[1024];
while (fs.Read(b, 0, b.Length) > 0)
{
Console.WriteLine(Encoding.UTF8.GetString(b));
}
} // Dispose() is called automatically here
The above code is equivalent to this:
FileStream fs = File.OpenRead("C:\\temp\\myfile.txt"))
try
{
// Read a text file 1024 bytes at a time and write it to the console
byte[] b = new byte[1024];
while (fs.Read(b, 0, b.Length) > 0)
{
Console.WriteLine(Encoding.UTF8.GetString(b));
}
}
finally
{
fs.Dispose();
}
The Disposing Pattern would be the best to use.
Here's the full implementation of your work.
Remember, that you have to call Dispose by your own like done in the code below.
public static void Main()
{
Panda[] forest_panda = new Panda[10];
for (int i = 0; i < forest_panda.GetLength(0); i++)
forest_panda[i] = new Panda("P1");
// Dispose the pandas by your own
foreach (var panda in forest_panda)
panda.Dispose();
for (int i = 0; i < forest_panda.GetLength(0); i++)
forest_panda[i] = new Panda("P1");
// Dispose the pandas by your own
foreach (var panda in forest_panda)
panda.Dispose();
Console.WriteLine("Total Pandas created is {0}", Panda.population);
}
class Panda : IDisposable
{
public static int population = 0;
public string name;
public Panda(string name)
{
this.name = name;
population = population + 1;
}
~Panda()
{
Dispose(false);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
population = population - 1;
}
}
}
It invoked for me in release build . However behaved differently in debug.
Possible Duplicate:
Should I Dispose() DataSet and DataTable?
OP comment: I would like to say that the "Should I Dispose() DataSet and DataTable?" link isn't a possible solution. It's a good link, but this is more design related. Instead, ignore that the exposed property is a DataSet and replace it with something that should be disposed. The same question would apply there.
I'm messing around with Crystal Reports, and I have a "ReportData" class. In other words, this class encapsulates the "Filling" of the DataSet I will use.
public class ReportData
{
private DataSet1 m_DS = null; // Notice this disposable member variable
public ReportData( ... some parameters ...)
{
m_DS = new DataSet1();
// Plus some other manipulation on m_DS
}
public DataSet1 GetDataSet
{
get
{
return m_DS;
}
}
// Everything else is pretty much private.
// This class is here to generate my DataSet
}
Here is how it would be used by some other class:
private void SetReportDataSource()
{
DataSet1 ds = m_RptData.GetDataSet;
m_Rpt.SetDataSource(ds);
}
I'm pretty much learning C# on the fly (read a couple of chapters in an intro book, and just went at it, googling everything along the way). From what I understand, if it implements IDisposable, you better Dispose it. A DataSet implements IDisposable, so we need to Dispose it.
Here's where the design part comes in:
Question 1a: Do I make my ReportData class IDisposable?
In other words, it looks like I could just do this and be done with it:
private void SetReportDataSource()
{
using (DataSet1 ds = m_RptData.GetDataSet)
{
m_Rpt.SetDataSource(ds);
}
}
Question 1b: Should I be more defensive in some way?
I don't know, I guess I'm really, really trying to ensure that it gets disposed. For example, taking my SetReportDatsSource function as an example. I used "using", but someone else may use the class and forget to add the using or call Dispose in some way. Therefore, I go to my ReportData class:
public class ReportData : IDisposable
{
private DataSet1 m_DS = null; // Notice this disposable member variable
private bool m_IsDisposed = false; // This is new!
public ReportData( ... some parameters ...)
{
m_DS = new DataSet1();
// Plus some other manipulation on m_DS
}
// New code here (up until the GetDataSet property)
~ReportData()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (m_IsDisposed == true)
{
return;
}
if (m_DS != null)
{
m_DS.Dispose();
m_DS = null;
}
m_IsDisposed = true;
}
// Done with new code
public DataSet1 GetDataSet
{
get
{
return m_DS;
}
}
// Everything else is pretty much private.
// This class is here to generate my DataSet
}
Now, let's go back to the calling class, we still have:
private void SetReportDataSource()
{
using (DataSet1 ds = m_RptData.GetDataSet)
{
m_Rpt.SetDataSource(ds);
}
}
But, I made ReportData (m_RptData) disposable now too! So, we are going to want to dispose of that! And because it's a member variable (and I can't just use "using" in the way I'm using it with SetReportDataSource), you start thinking about making this calling class IDisposable, so I can have:
protected virtual void Dispose(bool disposing)
{
if (m_IsDisposed == true)
{
return;
}
if (m_ReportData != null)
{
m_ReportData.Dispose();
m_ReportData = null;
}
m_IsDisposed = true;
}
So, now this class has the destructor/finalizer and its public Dispose method, disposing of ReportData. We're guaranteed that we dispose of the DataSet!
But then again, this will result in DataSet's Dispose method getting called twice. Because the SetReportDataSource function disposes the exposed DataSet, and the ReportData class is also disposing the same thing (and there is not an easy way to determine if someone disposed of the exposed DataSet).
Seems kind of nutty. It looks like to me that I:
a) May be overthinking this (or just trying to be really defensive, which is good)!
b) Might be jumping through a bunch of hoops.
Maybe the rule should be: If my class is going to expose it, the calling function should be responsible for disposing it.
The only issue I see with that (and that's why I posted here):
In between the time that ReportData member variable is instantiated, and SetReportDataSource is called, some error/exception may occur. So, we never get a chance to do the "using" (inside of SetReportDataSource) on our DataSet. But that dataset was constructed with ReportData (and we want to call dispose on it!)
So, now we're back to making ReportData IDisposable, because we are going to at least need some public "CleanUp" function ... ok, I'm done. :)
If you are holding onto something that implements IDisposable, the simplest pattern is to implement IDisposable yourself, and call the Dispose methods on all IDisposables you own. Being more defensive than doesn't seem feasible; if somebody using your class forgets to call your Dispose method, then how do you ever know they are done using you?
Edit: On second thoughts, a Finalize call tells you that your client is done using you; they have no more references to you...
Please see: Should I Dispose() DataSet and DataTable?
As has come up several times on SO, if an object it implements IDisposable then you should call Dispose(). [There are a few places in the .NET framework where the original designers, presumably thouight they would require Dispose() but then didn't need it. But the safest and correct thing to do would be to call Dispose regardless.]
You don't show the code for SetDataSource but this piece of code is only going to work if SetDataSource immediately consumes the contents of the DataSet and does not store a reference to it:
private void SetReportDataSource()
{
using (DataSet1 ds = m_RptData.GetDataSet)
{
m_Rpt.SetDataSource(ds);
}
}
As for the rest of your code and question (quoting a deleted answer):
you don't have anything that needs to be finalized. You might have noticed that when you found out that you had no use for the disposing argument. All you need is this:
void Dispose() {
if (m_DS != null) m_DS.Dispose()
}
The general rule for Finalizers is: When in doubt, Don't.
You will only need one when you directly use an unmanaged resource.
Answer 1A: I would recommend the using syntax, the reason for that is it seems to be the standard for handling things of this nature.
Answer 1B: If someone else is using your class, I assume you mean extending, it is on the implementer to handle any changes he sees fit. According to the docs on Dispose()
If an object's Dispose method is called more than once, the object must ignore all calls after the first one. The object must not throw an exception if its Dispose method is called multiple times. Dispose can throw an exception if an error occurs because a resource has already been freed and Dispose had not been called previously. (http://msdn.microsoft.com/en-us/library/system.idisposable.dispose%28VS.71%29.aspx)
The garbage collector will at some point get a hold of your object and handle it. Barring catastrophe.