C# What is the point of the using statement? [duplicate] - c#

This question already has answers here:
Why do we need Dispose() method on some object? Why doesn't the garbage collector do this work?
(2 answers)
What are the uses of "using" in C#?
(29 answers)
Closed 10 months ago.
I'm not talking about references to assemblies, rather the using statement within the code.
For example what is the difference between this:
using (DataReader dr = .... )
{
...stuff involving data reader...
}
and this:
{
DataReader dr = ...
...stuff involving data reader...
}
Surely the DataReader is cleaned up by the garbage collector when it goes out of scope anyway?

The point of a using statement is that the object you create with the statement is implicitly disposed at the end of the block. In your second code snippet, the data reader never gets closed. It's a way to ensure that disposable resources are not held onto any longer than required and will be released even if an exception is thrown. This:
using (var obj = new SomeDisposableType())
{
// use obj here.
}
is functionally equivalent to this:
var obj = new SomeDisposableType();
try
{
// use obj here.
}
finally
{
obj.Dispose();
}
You can use the same scope for multiple disposable objects like so:
using (var obj1 = new SomeDisposableType())
using (var obj2 = new SomeOtherDisposableType())
{
// use obj1 and obj2 here.
}
You only need to nest using blocks if you need to interleave other code, e.g.
var table = new DataTable();
using (var connection = new SqlConnection("connection string here"))
using (var command = new SqlCommand("SQL query here", connection))
{
connection.Open();
using (var reader = command.ExecuteReader()
{
table.Load(reader);
}
}

Such using statement automatically disposes the object obtained at the end of scope.
You may refer to this documentation for further details.

Related

Prevent object dispose inside using block

Workflow:
I have a winform app with two forms, in the 1st form I query a liteDB and it manipulates an IEnumerable<T> instance inside a using block with retrieved data.
IEnumerable<student> searchResult;
using(var db = new LiteDatabase(#"C:\Temp\MyData.db"))
{
var col = db.GetCollection<student>("students");
col.EnsureIndex(x => x.contact.phone);
searchResult = col.Find(x => x.contact.phone == "123456789");
}
Form2 frm2 = new Form2();
Form2.profileData = searchResult.AtElement(index);
Problem:
I then, need to send an element of searchResult<student> to 2nd form in order to show user, as you can see in the last 2 lines of above code.
But since it's inside using block, I get System.ObjectDisposedException.
Data types and exception:
studentCollection.Find():
searchResult:
Exception:
Addition:
What I already though of as possible way is:
Override and nullify existing dispose() method then call my own implemented method after I'm done; Which is basically equals to not having a using block, except that I don't have to take care of disposing other objects in above using block, but only searchResult<student>.
P.S:
I'm newbie at whole thing, appreciate the help and explanation
I'm not familliar with LiteDb, but I would assume it returns a proxy object for the database. So when the database is disposed, the proxy-object is no longer usable.
The simple method to avoid the problem is to add .ToList() after the .Find(...). This will convert the proxy-list to an actual List<T> in memory, and it can be used after the database is disposed. It is possible that the student objects inside the list are also proxies, and if that is the case this will fail.
If that is the case you either need to find some way to make the database return real, non-proxy objects, or extend the lifetime of the database to be longer than that of your form, for example
IList<student> myIList;
using(var db = new LiteDatabase(#"C:\Temp\MyData.db"))
{
var col = db.GetCollection<student>("students");
col.EnsureIndex(x => x.contact.phone);
myIList = col.Find(x => x.contact.phone == "123456789");
using(var frm2 = new Form2()){
frm2.profileData = myIList.AtElement(index);
frm2.ShowDialog(this);
}
}
Note the usage of .ShowDialog, this will block until the second form has been closed. That is not strictly necessary, but it makes it much easier to manage the lifetime of the database.
You need to access the element before exiting the using block.
using(var db = new LiteDatabase(#"C:\Temp\MyData.db"))
{
var col = db.GetCollection<student>("students");
col.EnsureIndex(x => x.contact.phone);
var searchResult = col.Find(x => x.contact.phone == "123456789");
Form2 frm2 = new Form2();
Form2.profileData = searchResult.AtElement(index);
}

"using" statement in C# - Is this a nested try/finally?

I've came across a code snippet like the following:
using (IDbCommand selectCommand = this.createCommand(selectSQL))
using (IDataReader theData = selectCommand.ExecuteReader())
{
while (theData.Read())
{
Phone aPhone = new Phone(...some code here...);
thePhones.Add(aPhone);
}
}
Now I am trying to learn the using statement in this context in by interpreting above code into old try/finally statement. From my understanding, the using statement will interpret the code after the brackets as try. In this case, try should enclose all the stuff after (IDbCommand selectCommand = this.createCommand(selectSQL)). However in this code, there is another using statement immediately comes after the first using.
Is it correct to interpret them as a nested try/finally statement in this context?
Using statements will automatically call Dispose() for any IDisposable object within it declaration. It's important to note that this is not a replacement for any try/catch/finally statements that your own code may need to do. The using statement ensures that Dispose() will be called if any code within it's block throws or not. This is extremely important any time I/O objects are used such as network calls, stream reading, database calls, etc. This will make sure you don't have memory leaks or locked files.
using (IDbCommand selectCommand = this.createCommand(selectSQL))
{
//an exception or not will call Dispose() on selectCommand
using (IDataReader theData = selectCommand.ExecuteReader())
{
//an exception or not will call Dispose() on theData
while (theData.Read())
{
Phone aPhone = new Phone(...some code here...);
thePhones.Add(aPhone);
}
}
}
The "equivalent" to running this code without using statements would be:
var selectCommand = this.createCommand(selectSQL);
try
{
var theData = selectCommand.ExecuteReader();
try
{
while (theData.Read())
{
Phone aPhone = new Phone(...some code here...);
thePhones.Add(aPhone);
}
}
finally
{
if (theData != null)
{
theData.Dispose();
}
}
}
finally
{
if (selectCommand != null)
{
selectCommand.Dispose();
}
}
However, the above code should not be used since the using statement is refined, optimized, guaranteed, etc, but the gist of it is above.
using (IDbCommand selectCommand = this.createCommand(selectSQL))
using (IDataReader theData = selectCommand.ExecuteReader())
{
}
At compile time will be converted to
using (IDbCommand selectCommand = this.createCommand(selectSQL))
{
using (IDataReader theData = selectCommand.ExecuteReader())
{
}
}
Just that. And it not related to try catch in anything
Yes, your code is interpreted as
using (IDbCommand selectCommand = this.createCommand(selectSQL))
{
using (IDataReader theData = selectCommand.ExecuteReader())
{
while (theData.Read())
{
Phone aPhone = new Phone(...some code here...);
thePhones.Add(aPhone);
}
}
}
which could be thought of as "nested try/finally blocks"
Using multiple using statements is just like with multiple if statements, you could do
if(foo)
if(bar)
{
DoStuff()
}
Which is the same as
if(foo)
{
if(bar)
{
DoStuff()
}
}

Using TransactionScope in Service Layer for UnitOfWork operations

Is my approach right to bundle all 3 dataprovider.GetXXX methods in a TransactionScope in the service layer as UnitOfWork?
Would you do something different?
From where does the TransactionScpe ts know the concrete ConnectionString?
Should I get the Transaction object from my connection and pass this Transaction objekt to the constructor of the TransactionScope ?
Service Layer like AdministrationService.cs
private List<Schoolclass> GetAdministrationData()
{
List<Schoolclass> schoolclasses = null
using (TransactionScope ts = new TransactionScope())
{
schoolclasses = _adminDataProvider.GetSchoolclasses();
foreach (var s in schoolclasses)
{
List<Pupil> pupils = _adminDataProvider.GetPupils(s.Id);
s.Pupils = pupils;
foreach (var p in pupils)
{
List<Document> documents = _documentDataProvider.GetDocuments(p.Id);
p.Documents = documents;
}
}
ts.Complete();
}
return schoolclasses;
}
Sample how any of those 3 methods in the DataProvider could look like:
public List<Schoolclass> GetSchoolclassList()
{
// used that formerly without TransactionSCOPE => using (var trans = DataAccess.ConnectionManager.BeginTransaction())
using (var com = new SQLiteCommand(DataAccess.ConnectionManager))
{
com.CommandText = "SELECT * FROM SCHOOLCLASS";
var schoolclasses = new List<Schoolclass>();
using (var reader = com.ExecuteReader())
{
Schoolclass schoolclass = null;
while (reader.Read())
{
schoolclass = new Schoolclass();
schoolclass.SchoolclassId = Convert.ToInt32(reader["schoolclassId"]);
schoolclass.SchoolclassCode = reader["schoolclasscode"].ToString();
schoolclasses.Add(schoolclass);
}
}
// Used that formerly without TransactionSCOPE => trans.Commit();
return schoolclasses;
}
}
This looks fine - that's what TransactionScope is there for, to provide transaction control in your code (and this is a common pattern for UoW).
From where does the TransactionScpe ts know the concrete ConnectionString?
It doesn't. That depends on your data access layer and doesn't really mean much to TransactionScope. What TransactionScope does is create a transaction (which will by default be a light-weight one) - if your data access spans several databases, the transaction will automatically be escalated to a distributed transaction. It uses MSDTC under the hood.
Should I get the Transaction object from my connection and pass this Transaction objekt to the constructor of the TransactionScope ?
No, no, no. See the above. Just do what you are doing now. There is no harm in nesting TransactionScopes.

Storing reader information in C#

I know what I asking might not make a lot of sense for C# experts but I'll explain what I want to do and then you can suggest me how to do it in a better way if you want ok?
I have a C# class called DatabaseManager that deals with different MySQL queries (ado.net NET connector, not linq or any kind of ActiveRecord-ish library).
I am doing something like
categories = db_manager.getCategories();
The list of categories is quite small (10 items) so I'd like to know what's the best way of accessing the retrieved information without a lot of additional code.
Right now I'm using a Struct to store the information but I'm sure there's a better way of doing this.
Here's my code:
public struct Category
{
public string name;
}
internal ArrayList getCategories()
{
ArrayList categories = new ArrayList();
MySqlDataReader reader;
Category category_info;
try
{
conn.Open();
reader = category_query.ExecuteReader();
while (reader.Read())
{
category_info = new Category();
category_info.name = reader["name"].ToString();
categories.Add(category_info);
}
reader.Close();
conn.Close();
}
catch (MySqlException e)
{
Console.WriteLine("ERROR " + e.ToString());
}
return categories;
}
Example:
public IEnumerable<Category> GetCategories()
{
using (var connection = new MySqlConnection("CONNECTION STRING"))
using (var command = new MySqlCommand("SELECT name FROM categories", connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
yield return new Category { name = reader.GetString(0) };
}
}
}
}
Remarks:
Let ADO.NET connection pooling do the right work for you (avoid storing connections in static fields, etc...)
Always make sure to properly dispose unmanaged resources (using "using" in C#)
Always return the lowest interface in the hierarchy from your public methods (in this case IEnumerable<Category>).
Leave the callers handle exceptions and logging. These are crosscutting concerns and should not be mixed with your DB access code.
The first thing I would do is to replace you use of ArrayList with List that will provide compile-time type checkig for your use of the category list (so you will not have to type cast it when using it in your code).
There's nothing wrong with returning them in an like this. However, a few things stand out:
Your catch block logs the error but
then returns either an empty array or
a partially populated array. This
probably isn't a good idea
If an exception is thrown in the try
block you won't close the connection
or dispose of the reader. Consider
the using() statement.
You should use the generic types
(List<>) instead of ArrayList.
From your code I guess you are using .NET 1.1, becuase you are not using the power of generics.
1) Using a struct that only contains a string is an overkill. Just create an arraylist of strings (or with generics a List )
2) When an exception occurs in your try block, you leave your connection and reader open... Use this instead:
try
{
conn.open();
//more code
}
catch (MySqlException e) { // code
}
finally {
conn.close()
if (reader != null)
reader.close();
}

DataReader associated with this Command which must be closed first

I am getting the following error;
"There is already an open DataReader associated with this Command which must be closed first."
is it because I have used the reader in foreach loop ? or what the problem might be ?
Regards
BK
foreach( Apple a in listApple )
{
....
using (SmartSqlReader reader = Db.CurrentDb.ExecuteReader(sp))
{
while (reader.Read())
{
a.blablabla += reader.GetInt32("BLA_BLA_BLA");
}
}
.....
}
Have you implemeneted the SmartSqlReader to close when it's disposed? The regular data readers implement the IDisposable interface and calls Close from the Dispose method.
If you don't close it properly it will keep the Command object occupied until the garbage collector will find the reader and clean it up.
Try the following:
using (SmartSqlReader reader = Db.CurrentDb.ExecuteReader(sp))
{
while (reader.Read())
{
a.blablabla += reader.GetInt32("BLA_BLA_BLA");
}
reader.Close();
}
Add reader.Close() to close the SmartSqlReader

Categories

Resources