The using keyword only calls the .Dispose() method. If you have the necessary cleanup that happens outside of the dispose method on the IDisposable, then you will need to do this in your own finally block. This leads to two points:
- At this point, you can argue that you can also skip the use block and simply call Dispose () inside the finally block. Personally, I will still go with the
using block. It is just a good habit to always have one for your IDisposable instances. - I humbly suggest that if you consider the conditions above, you need to redesign your class to use the IDisposable template.
Based on the code you posted, the problem is that your options were still rooted somewhere (maybe you are reusing them?). Since the parameters are still rooted, they cannot be collected. They also contain a link to the command to which they are attached, so your SqlCommand object also cannot be built right away, because now it is still rooted.
The key point is that the .Net framework reserves the Dispose () pattern for unaudited resources. Since SqlParameters and SqlParameterCollection are type-driven, they are not affected until they are assembled, which is completely separate from the deletion. When your SqlCommand is finally built, it will also take care of the SqlParameter collection. Just do not confuse the collection, removal and their goals.
What you want to do is make a copy of each parameter when you add it, and not add an existing parameter to the collection.
public static DataTable GetDataTable(string cmdText, IEnumerable<Parameter> parameters) {
Some things to note here: I was able to get rid of all your try blocks. None of them are needed. In addition, the SqlDataAdapter.Fill () method will open and close the connection for you, so you do not need this part.
Now let's talk about this CloneParameter () function. I get the impression that you feel that this violates the purpose of your code, and this is an attempt to reuse the parameters. I promise you that reusing this option is a bad idea. The performance degradation is negligible, especially compared to performing stored procedures. I left you the implementation of CloneParameter () for two reasons: first of all, this is trivial, and secondly, we are already outside of my usual data access pattern. Typically, to add parameters, I accept an Action <SqlParameterCollection> delegate, not a parameter that can be enumerated. The function is declared as follows:
public IEnumerable<IDataRecord>GetData(string cmdText, Action<SqlParameterCollection> addParameters)
and is called like this:
foreach(var record in GetData("myprocedurename", p => { p.Add( ); p.Add( );
Since you are filling two tables in a row, it looks like you are working on the client side, which may justify this against the DataReader / IEnumerable approach, but I want to mention this, since most of the time your code is based in DataReader is the best option.
What would I do in your case with my existing Action-delegate-based template and wanting to reuse a duplicate set of parameters as much as possible, there is a real named method that knows how to add parameters and matches my delegate for actions. Then I could just pass this method and get the desired parameter reuse.