5

I am using the Memory Management while returning the data like below.

private DataSet ReturnDs()
{
    using (DataSet ds = new DataSet())
    {
        return ds;
    }
}

Query - Is there any issue in placing the 'Using' Statement while returning the data? I am Still getting the complete schema as well as the data in the receiving function?

  • 2
    If you want to return an object, why would you want to dispose it? – Mert Akcakaya Aug 05 '12 at 11:21
  • @Mert - I want to know what's the harm ? Is there any loss in data? I verified that It is ok...My question is - is there anything non-advantageous that i am missing ? –  Aug 05 '12 at 11:22
  • You verified it? Nice. Way too few people actually prove their code with formal methods :) – Joey Aug 05 '12 at 11:24
  • 1
    Related reading: http://stackoverflow.com/questions/913228/should-i-dispose-dataset-and-datatable – Marc Gravell Aug 05 '12 at 11:40

5 Answers5

4

This is definitely a wrong pattern. The only reason that it is working for you now is that DataSet.Dispose() is actually a dummy.

using (DataSet ds = new DataSet())
{
    return ds;
}  // there is a ds.Dispose() here but it does nothing.

If you replace the DataSet with for instance an Enitity framework DbContext then you would not see any data in the calling function.

H H
  • 263,252
  • 30
  • 330
  • 514
  • +1 Any object that actually does something meaningful in its `Dispose` method would appear "invalid" in the calling method. – user703016 Aug 05 '12 at 11:29
  • @HenkHolterman - can you please share a link to explain **there is a ds.Dispose() here but it does nothing**. –  Aug 06 '12 at 16:20
  • @ChrisGessler explains using => Dispose, for Dataset.Dispose just google or look up the source code. – H H Aug 06 '12 at 16:47
4

In general terms, disposing an object you are about to return is an error: your code hasn't finished with that object, and yo will be handing a broken object to the caller.

So indeed: don't Dispose() that, which means: don't use using on an object you will return. It is up to the caller to dispose it: they are the owner now. Of course, this should ideally be documented in the API.

More generally, though, you need to think about exceptions too. What happens if your method errors? For complex scenarios, you may need something like:

SomeType foo = null;
try {
    // initialize and populate foo - this could error half-way through
    return foo;
} catch {
    if(foo != null) foo.Dispose();
    throw;
}

to ensure that the object is disposed correctly in the failure case.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • +1 Because you're saying the same thing as Henk. Also strictly speaking it's not an error, it's just useless and meaningless to return what can (and generally will) be a dead object to a caller. – user703016 Aug 05 '12 at 11:34
  • @RGI that is because for DataSet, Dispose is a no-op: http://stackoverflow.com/questions/913228/should-i-dispose-dataset-and-datatable And hence why I answered *in the general case*. However, what you are doing is confusing and could lead to errors for any other type. Don't do it. – Marc Gravell Aug 05 '12 at 11:39
  • sir, can you kindly tell us something about `objectDisposedException` ? –  Aug 05 '12 at 17:04
  • @RGI it is a well-known exception that authors of IDisposable components *can* use to indicate the object is already disposed, but are not **forced** to use. – Marc Gravell Aug 05 '12 at 17:28
2

Use the using statement in the calling method, not the method returning the object.

public void Caller()
{
  using(DataSet ds = GetDataSet())
  {
    // code here
  }
}

public DataSet GetDataSet()
{
  // don't use a using statement here
  return ds;
}

The using statement is basically the same as doing this:

DataSet ds = null;
try
{
  // code here
}
finally
{
  if(ds != null)
  {
    ds.Dispose();
    ds = null;
  }
}

So, if you used a using statement in a method that is supposed to return the object in the using statement, it would return a Disposed object (i.e. closed stream, closed dataset, etc...)which means some of the internal objects could be null, or closed. In other words, all of the internal resources would be cleaned up, which is the purpose of implementing IDisposable in the first place. If your application relied upon some of these internal resources to be available, for example when using a Stream object, it would throw an exception.

Also keep in mind that not all finally blocks are written the same. Remember, IDispoable was implemented to clean up any INTERNAL resources and unmanaged objects. Those internal resources may not be needed outside the using statement, so sometimes using the using statement as you have may appear to work properly but it is not recommended, and definately won't work with all objects. If Microsoft decided to change the DataSet object in a future release, disposing of something vital to your application, then your working code would suddenly stop working.

Chris Gessler
  • 22,727
  • 7
  • 57
  • 83
  • @Chris we all got them. Not sure why. Minor point: you wouldn't be able to get a null reference just by disposing. I can't see the votes against my own post (for obvious reasons), but the downvote against yourself is not from anyone who has actively participated in any way on this question. I'd just write it off as "one f those things". – Marc Gravell Aug 05 '12 at 15:00
  • @MarcGravell - thanks, but I'm referring to the internal references being null, not the object itself. Whenever I implement IDisposable and clean up an array for example, I always set the internal reference to null. It would be impossible to set the object itself to null within itself. I rephrased for clarity – Chris Gessler Aug 05 '12 at 15:04
  • 1
    @ChrisGessler ah, I see what you mean; indeed, in the general case you could start getting bizarre errors; ObjectDisposedException if the coder remembered to check - NullReferenceException otherwise. See also the edit – Marc Gravell Aug 05 '12 at 15:05
  • @MarcGravell - good point on the ObjectDisposedException. I almost forgot about that one. Thanks. – Chris Gessler Aug 05 '12 at 15:09
0

I'm not sure what exactly your question is.

Once the method ends by retunring something, ds.Dispose() will automatically be called.

This means that the DataSet your method returns will already be disposed when your calling method receives it.

Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
0

as Mert comment, note that you're disposing the object you're return. but basically, the using is actually a try/finally and the dispose will be called the method return. The effect is depends on the IDisposable implementation for each type. usually, you're not suppose to dispose (kill) the entity you're return to caller that probably gonna use it.

Tamir
  • 3,833
  • 3
  • 32
  • 41