troubles with finally statement and objects

G

Guest

Hi,

I am using the try catch finally block in many places in my code.

When a create an sqldatareader dr and try to close it in my
finally block I get the error: use of unsigned local variable.

dr.close();
works fine in the try but not in the finally.

How can I access my local objects in the finally without these errors?

thanks

Chris
 
N

Nicholas Paldino [.NET/C# MVP]

Chris,

You should be doing something like this:

// Delcare the reader.
SqlDataReader reader = null;

// Use the reader here.
try
{
// Create the reader.
reader = new SqlDataReader(...);

// Use the reader.
}
catch
{
}
finally
{
// Check the reader for null. If it is not, then
// dispose.
if (reader != null)
{
// Dispose of it.
((IDisposable) reader).Dispose();
}
}

This should compile just fine. Chances are you missed the null
assignment to the variable declaration.

Hope this helps.
 
S

Siva M

Looks like the variable dr is declared inside try block - dr is only local
to try {} and not accessible in finally block. For your case, decalre dr
outside the try block so that you can access it in both try as well as
finally blocks.

Hi,

I am using the try catch finally block in many places in my code.

When a create an sqldatareader dr and try to close it in my
finally block I get the error: use of unsigned local variable.

dr.close();
works fine in the try but not in the finally.

How can I access my local objects in the finally without these errors?

thanks

Chris
 
N

Nick Malik [Microsoft]

Chris said:
Hi,

I am using the try catch finally block in many places in my code.

When a create an sqldatareader dr and try to close it in my
finally block I get the error: use of unsigned local variable.

dr.close();
works fine in the try but not in the finally.

How can I access my local objects in the finally without these errors?

Hi Chris,

In addition to the excellent answers given so far, there is another
construct of C# that you may not be aware of.

You are clearly being a good citizen and cleaning up the data reader during
error handling. However, C# has a pretty nice construct that will call the
..Dispose method for you... it is called 'using'

I snatched a bad example of using the Data Reader object from a random site
and rewrote it to use the 'using' statement, here:

SqlDataReader data;
using (data = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while( data.Read() )

{
Console.WriteLine("Company Name " +
data.GetString(data.GetOrdinal("CompanyName"));

}
} // automatically calls data.Dispose();

Here is the spec page in the MSDN. It's a very cool capability of the
language, and reduces your code brilliantly.
Note: you still need a try-catch-finally, but you won't need to close the
data reader, because leaving that block of 'using' code, FOR ANY REASON,
will call Dispose for you.

http://msdn.microsoft.com/library/d...ry/en-us/csspec/html/vclrfcsharpspec_8_13.asp


--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
--
 
J

Jon Skeet [C# MVP]

Nick Malik said:
I snatched a bad example of using the Data Reader object from a random site
and rewrote it to use the 'using' statement, here:

SqlDataReader data;
using (data = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while( data.Read() )

{
Console.WriteLine("Company Name " +
data.GetString(data.GetOrdinal("CompanyName"));

}
} // automatically calls data.Dispose();

That would be better written IMO as:

using (SqlDataReader data = command.ExecuteReader
(CommandBehavior.CloseConnection))
{
while( data.Read() )
{
Console.WriteLine("Company Name " +
data.GetString(data.GetOrdinal("CompanyName"));

}
} // automatically calls data.Dispose();

There's no point in letting the variable have a wider scope than the
using block, and it's better to give it the smallest scope it needs.
Here is the spec page in the MSDN. It's a very cool capability of the
language, and reduces your code brilliantly.

Agreed.
 
N

Nick Malik [Microsoft]

Jon Skeet said:
That would be better written IMO as:

using (SqlDataReader data = command.ExecuteReader
(CommandBehavior.CloseConnection))
{
while( data.Read() )
{
Console.WriteLine("Company Name " +
data.GetString(data.GetOrdinal("CompanyName"));

}
} // automatically calls data.Dispose();

There's no point in letting the variable have a wider scope than the
using block, and it's better to give it the smallest scope it needs.

Thanks, Jon. That's what I get for rewriting something I snatch off of a
web site. I agree with your change completely.

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
--
 
S

Scott Roberts

SqlDataReader data;
using (data = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while( data.Read() )

{
Console.WriteLine("Company Name " +
data.GetString(data.GetOrdinal("CompanyName"));

}
} // automatically calls data.Dispose();

Why don't I like that? Is it because it's new and I'm not used to it? I want
to see the call to Close() in there somewhere. Am I becoming old and set in
my ways?
 
J

Jon Skeet [C# MVP]

Why don't I like that? Is it because it's new and I'm not used to it? I want
to see the call to Close() in there somewhere. Am I becoming old and set in
my ways?

I hope it's just because you're not used to it. The "using" statement
is one of the top things I prefer about C# to Java, despite it only
being syntactic sugar. It makes things *much* more readable (admittedly
only when you know what the using statement does!), and makes it far
simpler to "get it right" when it comes to disposing of things.
 
S

Scott Roberts

Jon Skeet said:
It makes things *much* more readable (admittedly
only when you know what the using statement does!), and makes it far
simpler to "get it right" when it comes to disposing of things.

I know what "using" does, so I don't think that's it. I don't know what
happens in Dispose() of every single class in the .NET library. Perhaps
that's it. I'd like to see Close() then Dispose() to be sure Close()
actually happened. Perhaps this is paranoia on my part. If so, hopefully
I'll get over it.
 
J

Jon Skeet [C# MVP]

Scott Roberts said:
I know what "using" does, so I don't think that's it. I don't know what
happens in Dispose() of every single class in the .NET library. Perhaps
that's it. I'd like to see Close() then Dispose() to be sure Close()
actually happened. Perhaps this is paranoia on my part. If so, hopefully
I'll get over it.

If Dispose() doesn't correctly deal with a resource, then it's a bug -
but you could just as easily have the bug in Close as in Dispose. Note
that making sure you call both Close *and* Dispose involves having
*two* finally blocks, making the code even harder to read :)

As you say, hopefully you'll get over it :)
 
C

Cor Ligthert [MVP]

Chris,

You can set a try block nested which is very nice for this kind of
operations.

try{open whatever;
try{}catch{}
}
catch{}
finally{close whatever;}

I hope this helps,

Cor
 
G

Guest

Thanks Everyone for your responses.

I am having trouble finding the namespace that provides me with the
command: CommandBehavior.CloseConnection.

I'm getting the type or namespace missing error.
Could someone direct me how get it up and running. I have a hunch it's not
really
my namespace missing but a scope issue?

thanks

chris
 
J

Jon Skeet [C# MVP]

Chris said:
Thanks Everyone for your responses.

I am having trouble finding the namespace that provides me with the
command: CommandBehavior.CloseConnection.

I'm getting the type or namespace missing error.
Could someone direct me how get it up and running. I have a hunch it's not
really my namespace missing but a scope issue?

CommandBehavior is an enumeration in the System.Data namespace.

If that doesn't help, perhaps you could give an example of how you're
trying to use it?
 
C

Chris Dunaway

Jon said:
using (SqlDataReader data = command.ExecuteReader
(CommandBehavior.CloseConnection))

What would happen if the ExecuteReader command returned null? Does the
using construct check for null before it calls .Dispose?
 
S

Scott Roberts

Chris Dunaway said:
What would happen if the ExecuteReader command returned null?

I don't see "null" listed as a possible return value.
Does the
using construct check for null before it calls .Dispose?

In general, I would expect to get an exception if the "using" statement was
executed on "null".
 
J

Jon Skeet [C# MVP]

Chris Dunaway said:
What would happen if the ExecuteReader command returned null? Does the
using construct check for null before it calls .Dispose?

Yes. From the C# spec (reformatted with sane bracing):

<quote>
A using statement of the form

using (R r1 = new R())
{
r1.F();
}

is precisely equivalent to

R r1 = new R();
try
{
r1.F();
}
finally
{
if (r1 != null) ((IDisposable)r1).Dispose();
}
</quote>
 
J

Jon Skeet [C# MVP]

Scott Roberts said:
In general, I would expect to get an exception if the "using" statement was
executed on "null".

No - you won't get an exception unless the body of the using statement
tries to dereference the null value.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top