问题
I was looking at some code and discussing it with co-workers.
Specifically a section of code that looks like this.
[Test]
public void TestNormalWay()
{
using(var cn = GetConnection())
{
cn.Open();
// do stuff
}
}
The question came up:
"why not move the cn.Open into the GetConnection method."
I said that if "Open" throws an exception dispose would not get called. His response was
"So what. The connection wasn't opened so why would it need to get closed (or disposed)?"
For me it is just a matter of not wanting to know if or if not I NEED to dispose/close so I would repeat the cn.Open in the code instead of moving it into the shared function.
BUT it is interesting... so I did some reading at SQL Server Connection Pooling (ADO.NET)
To me it isn't clear if there exists a scenario in which calling cn.Open and it throws and exception where dispose would need to be called.
So in my example below is there any difference really between "TestNormalWay" and "WhyNotDoItThisWay"
protected static DbConnection GetConnection()
{
DbConnection cn = new SqlConnection("SomeConnecitonstring... ");
return cn;
}
protected static DbConnection GetConnectionDangerousVersion()
{
DbConnection cn = new SqlConnection("SomeConnecitonstring... ");
cn.Open(); // this will throw.. .dispose not called
return cn;
}
[Test]
public void TestNormalWay()
{
using(var cn = GetConnection())
{
cn.Open();
// do stuff
}
}
[Test]
public void WhyNotDoItThisWay()
{
using(var cn = GetConnectionDangerousVersion())
{
// do stuff
}
}
回答1:
The way you're writing your code you always want to open the connection as soon as it's created so there is no difference.
However you can open and close a connection several times and in code designed to do that there is a big difference.
I might want to write some code where I have a long running routine that takes a connection object and over time opens and closes it. The routine might not care how the connection object was created. Therefore it's an advantage to separate the act of creating the connection with the act of opening and closing it.
With regards the resource management question I'd agree it's not an issue. Creating an SQL connection object in itself doesn't lock any resources, it's the act of opening it that acquires a pooled connection. If the open returns an exception I think it's reasonable to assume that the connection wasn't opened.
回答2:
I would be inclined to just return the instance of the SqlConnection
without calling Open()
in your method. That should be done if and when it is needed. It is not needed in your utility function.
One of the reasons is, there are some objects that require a SqlConnection
, but don't necessarily need them to be opened. For instance, a SqlDataAdapter
takes a SqlConnection
, and handles the opening and closing of it within itself. Sure, you can open a connection before passing it, but then you have to be explicit with closing it.
Taking a few steps back, it should be the responsibility of the calling code to handle what exactly to do with the SqlConnection
.
回答3:
You could put a try/catch around the .Open() call in the second "dangerous" version so that if it does throw an exception while opening you are still disposing the connection.
回答4:
After peaking at the internals of SqlConnection I'm pretty much convinced that it really doesn't matter. A quick test seems to confirm this:
static void Main( string[] args )
{
Func<SqlConnection> getConnection =
() =>
{
var connection =
new SqlConnection(
"Initial Catalog=myDatabase;Server=(local);Username=bogus;password=blah;Connect Timeout=10;" );
connection.Open();
return connection;
};
while(true)
{
try
{
using( var connection = getConnection() )
{
var cmd = new SqlCommand( "SELECT 1", connection ) {CommandType = CommandType.Text};
cmd.ExecuteNonQuery();
}
}
catch ( Exception )
{
// ignore exception
}
}
}
I left this code running for a couple of minutes with a profiler attached. Not only is it running quite fast, it's also not leaking any memory. This pretty much convinces me it is ok to open the connection in your GetConnection method.
Of course all other arguments posted here are still valid; you should only open the connection if you're going to use it right away.
来源:https://stackoverflow.com/questions/9316981/using-statement-with-connection-open