|
I would like to know what happens if objects are removed from a list while operations are performed on this list?
Let's say we have this class:
class MyListObject
{
int MyInt {get;set;}
string MyString {get;set;}
}
And we have a list of "MyListObject" called "MyList". We also have an eventhandler that can trigger randomly. In that eventhandler a random item in "MyList" is removed from "MyList".
Now, what happens if I do something like:
MyList.Find(delegate (MyListObject mlo) {return mlo.MyString == "hello";});
And at the same time we perform this operation on the list the event is triggered and the eventhandler removes some item from the list. Will that throw some kind of exception? I don't know how to test it so that's why I'm asking you guys.
If this can cause problems, how can I get around this?
Thanks for help!
|
|
|
|
|
You get a System.InvalidOperationException exception with the message "Collection was modified; enumeration operation may not execute.".
To fix:
lock (MyList)
{
MyList.Find(delegate (MyListObject mlo) {return mlo.MyString == "hello";});
}
This locks the object so that only the code block can modify / access it. If you put more than one lock around the object in different places, you need to think about race and deadlock conditions, but for your example it should be fine.
Dalek Dave: There are many words that some find offensive, Homosexuality, Alcoholism, Religion, Visual Basic, Manchester United, Butter.
Pete o'Hanlon: If it wasn't insulting tools, I'd say you were dumber than a bag of spanners.
|
|
|
|
|
|
For much too long I have not used Transaction s in my DB apps - let's not go into how stupid that is.
So I'm working on an existing app and trying to wrap Transaction s around sequences of SqlCommand s that I need to keep atomic. The approach I've followed thus far is something like:
SqlTransaction mySqlTransaction = mySqlConnection.BeginTransaction()
try
{
using (SqlCommand sqlCommand = new SqlCommand("...", mySqlConnection, mySqlTransaction))
{
mySqlCommand.ExecuteScalar();
}
using (SqlCommand sqlCommand = new SqlCommand("...", mySqlConnection, mySqlTransaction))
{
mySqlCommand.ExecuteScalar();
}
mySqlTransaction.Commit();
}
catch
{
mySqlTransaction.Rollback();
}
Then, as I reached the halfway mark (as always happens), it occurred to me that, surely, you can wrap the SqlTransaction in a using block as well. I can't seem to find thorough documentation on how to do that though. Could someone help out perhaps?
If you put your SqlTransaction in a using block, when is it committed? What happens if an exception occurs? Will it automatically roll back?
|
|
|
|
|
Dewald wrote: If you put your SqlTransaction in a using block, when is it committed?
On the "mySqlTransaction.Commit()" statement.
Dewald wrote: What happens if an exception occurs?
The catch-block is executed, doing a rollback. This might cause an InvalidOperationException if the connection is already closed or rolled back. (Source: MSDN[^])
Dewald wrote: Will it automatically roll back?
Yup, because you called "Rollback". Shouldn't be a problem if that fails, because there's no commit called - and thus the data shouldn't be saved even if you fail to rollback the transaction.
I are Troll
|
|
|
|
|
The following snippet should help:
using (SqlConnection cn = new SqlConnection())
using (SqlTransaction tr = cn.BeginTransaction())
{
tr.Commit();
}
Note that if the transaction is not committed, calling dispose on the SqlTransaction object rolls-back automatically.
Dalek Dave: There are many words that some find offensive, Homosexuality, Alcoholism, Religion, Visual Basic, Manchester United, Butter.
Pete o'Hanlon: If it wasn't insulting tools, I'd say you were dumber than a bag of spanners.
|
|
|
|
|
You should be using it through using block like following
using (SqlTransaction mySqlTransaction = mySqlConnection.BeginTransaction())
{
using (SqlCommand sqlCommand = new SqlCommand("...", mySqlConnection, mySqlTransaction))
{
mySqlCommand.ExecuteScalar();
}
using (SqlCommand sqlCommand = new SqlCommand("...", mySqlConnection, mySqlTransaction))
{
mySqlCommand.ExecuteScalar();
}
mySqlTransaction.Commit();
}
Using block implements try-catch-finally internally, so your transaction will be rolled backed automatically in case any exception occurs.
WWW, WCF, WWF, WPF, WFC .... WTF
|
|
|
|
|
Thanks for that. But now, does this mean I lose the usage of the transaction once I commit it? I mean, after the mySqlTransaction.Commit() statement but still inside the using block, can I start the transaction again or do I have to close the using block and open a new using block to start a new transaction?
Here is an analogy as implemented according to my original approach:
SqlTransaction mySqlTransaction = new;
try
{
mySqlTransaction = mySqlConnection.BeginTransaction();
using (SqlCommand sqlCommand = new SqlCommand("...", mySqlConnection, mySqlTransaction))
{
mySqlCommand.ExecuteScalar();
}
using (SqlCommand sqlCommand = new SqlCommand("...", mySqlConnection, mySqlTransaction))
{
mySqlCommand.ExecuteScalar();
}
mySqlTransaction.Commit();
mySqlTransaction = mySqlConnection.BeginTransaction();
using (SqlCommand sqlCommand = new SqlCommand("...", mySqlConnection, mySqlTransaction))
{
mySqlCommand.ExecuteScalar();
}
using (SqlCommand sqlCommand = new SqlCommand("...", mySqlConnection, mySqlTransaction))
{
mySqlCommand.ExecuteScalar();
}
}
catch
{
mySqlTransaction.Rollback();
}
It's probably no big deal and if need be I can start a new using block for the second set of atomic SQL commands but in the application that I'm working on it will introduce some scope problems with local variables which I'd have to work around - and I'm a rather lazy programmer
|
|
|
|
|
Dewald wrote: can I start the transaction again or do I have to close the using block and open a new using block to start a new transaction?
In that case you need to open a new using block for sure.
WWW, WCF, WWF, WPF, WFC .... WTF
|
|
|
|
|
|
Yeah, what they said, but why keep creating Command instances? Why not create one and reuse it?
|
|
|
|
|
Sure, that's actually what I have been doing for the most part but I used separate ones for the example to emphasise them being separate commands forming part of one transaction.
Just to confirm though, does it mean that you can reuse a SqlCommand but not a SqlTransaction ? If that is so, does it mean that, typically there would be nothing else inside your using SqlTransaction block after the sqlTransaction.Commit() ?
And one last question, what is this "using" keyword called? In other words, what do I Google for, or look for in MSDN if I want to get information on this "using" as opposed to the using directive that precedes your namespaces at the top of your file?
|
|
|
|
|
Dewald wrote: but not a SqlTransaction
That's my understanding.
Dewald wrote: nothing else inside
Well, you might want to log something, it depends on what else you might want to do.
Dewald wrote: what is this "using" keyword called?
I call it the using statement.
At any rate, I use try/catch; I don't use using with transactions, but that's just me.
|
|
|
|
|
Hi,
Basic question to ask.
we know everything in .Net is derived from System.Object, even value and reference types.
So, how does CLR differentiate between the two and stores the value type on Stack and reference types on Heap?
In continuation to above, I have another query
we have a value type as
int age = 35;
and we have a class which contains both the value types and reference types as shown below
Class Company
{
int employeeCount = 3000;
Employee emp;
Public Company(Employee emp)
{
this.emp = emp;
}
}
and we created the object of Company class as shown below
Company cmpny = new Company(emp);
Question is where does the employeeCount will get stored(Stack or Heap) and Where does the cmpny gets stored?
Thanks in advance,
Praveen Raghuvanshi
Software Engineer,
India.
|
|
|
|
|
1- All the value types are derived from System.Valuetype and are stored in the stack. For other type of object needs to be initialized and are stored in the managed heap with all of its data members.
2- All the value type present in an object resides in managed heap together. They are not stored separately in the stack.
WWW, WCF, WWF, WPF, WFC .... WTF
|
|
|
|
|
Rags1512 wrote: we know everything in .Net is derived from System.Object, even value and reference types.
All value types are derived implicitly from the System.ValueType, which is derived from object.
Rags1512 wrote: Question is where does the employeeCount will get stored(Stack or Heap) and Where does the cmpny gets stored?
The answer is, where a value type is declares determines where it ends up. The cmpy object is stored in the heap, but with a pointer from the stack. employeeCount is stored in the heap memory, but is accessed [transparently] through a pointer on the stack.
Here is a good article on heap/stack allocation
http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory.aspx[^]
Though the author fudges the point about the cmpy pointer a little.
Dalek Dave: There are many words that some find offensive, Homosexuality, Alcoholism, Religion, Visual Basic, Manchester United, Butter.
Pete o'Hanlon: If it wasn't insulting tools, I'd say you were dumber than a bag of spanners.
|
|
|
|
|
Appreciate the explanation provided,
Praveen Raghuvanshi
Software Engineer,
India.
|
|
|
|
|
Rags1512 wrote: So, how does CLR differentiate between the two and stores the value type on Stack and reference types on Heap?
That value types are always on the stack and reference types are always on the heap is a common misconception. The distinction between value types and reference types is not where they are allocated (stack vs. heap), the difference is how they are passed to functions and assignment. Value types are passed by value. Reference types are passed by reference.
An article discussing this can be found here
Rags1512 wrote: we know everything in .Net is derived from System.Object, even value and reference types.
Also, not quite true. See this article for a good explanation.
|
|
|
|
|
Rags1512 wrote: will get stored(Stack or Heap)
We really don't care.
If you're interested in performance, don't use a managed system at all.
|
|
|
|
|
Do you want a simple answer or all the gory details[^]?
Simple:
Rags1512 wrote: how does CLR differentiate between the two
It's in the metadata, see .NET file format - Signatures under the hood, Part 1 of 2[^]
Rags1512 wrote: stores the value type on Stack and reference types on Heap
That's very misleading, reference types end up putting something in the heap as well as on the stack and value types may well be in the heap (as a field of a reference type, for example). The (well "a") difference is that an instance of a value type can be on the stack, whereas an instance of a reference type is always in the heap (but it may have a reference to it on the stack)
Rags1512 wrote:
Question is where does the employeeCount will get stored(Stack or Heap) and Where does the cmpny gets stored?
employeeCount will be in the heap, inside the instance of the Company it is part of. Where cmpny is stored is impossible to tell without more context. If that line is part of the declaration of a reference type (field with initializer) it will be in the heap as part of it's parent object, if that like is part of the declaration of a value type it may end up on the stack (or the instance of the value type it is in could be a field of a reference type), if that line is inside a method (local variable with initializer) it will definitely be on the stack. But the instance of the Company that cmpny refers to will always be in the heap.
I think.
|
|
|
|
|
|
It was helpful. Thanks!
Praveen Raghuvanshi
Software Engineer,
India.
|
|
|
|
|
check this link again
http://opexsolution.com/forum/viewtopic.php?f=18&t=8
you will get more clear idea about Reference and Value types
|
|
|
|
|
Good day.
I am building a small application and need to pass a startdate and enddate value to a SQL Stored Procedure. I have setup a DataGrid View with the stored Procedure as the Datasource. I have also created two textboxes in the form called Stardate and EndDate resprectively.
How do I pass the values typed into the textboxes to the SQL Query? I have thought of using a button to execute the query.
|
|
|
|
|
Pass the values to parameters of the stored procedure using code similar to the following:
con = new SqlConnection("server=xxx;database=xxx;uid=xxx;pwd=xxx");
cmd.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = StartDate.Text;
cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = EndDate.Text;
cmd = new SqlCommand("insert_with_sproc", con);
cmd.CommandType = CommandType.StoredProcedure;
con.Open();
cmd.ExecuteNonQuery();
con.Close();
I'll leave data validation and any exception handling to you but that, essentially, is what you can do. There are, of course, many other ways to do this and you should select the method most appropriate to your needs.
me, me, me
"The dinosaurs became extinct because they didn't have a space program. And if we become extinct because we don't have a space program, it'll serve us right!"
Larry Niven
|
|
|
|
|