Reputation: 5619
I had a problem where I was getting data returned in a IQueryable object and it was repeated. I solved it by moving the temp object that was used to build the collection from method scoped to loop scoped. In other words it gets wiped out each time the loop repeats.
Original:
private void MyMethod()
{
SomeObj ProjDtl = new SomeObj(); //here is the obj method scoped
foreach (ReservedSimProjects item in parameters.ReservedProjects.ReservedSimProj)
{
IQueryable<SJ> DbProj = SimColl.Where(e => e.SimProjectID == item.ProjectId);
ProjDtl.ProjName = DbProj.First().ProjName;
ProjDtl.ProjArea = DbProj.First().ProjArea;
ProjDtl.ProjPerim = DbProj.First().ProjArea;
....etc....
ProjectsDetails.Add(ProjDtl);
}
Now to my obviously incorrect thinking ProjDtl would be created once and reused. Old values would be overwritten with new values as the loop iterates. And that seemed to be exactly what was happening. Stepping through the debugger the ProjDtl properties were being overwritten but then the last line where it was added to the collection the original from the first pass was added thus my collection had duplicates, triplicates etc. Changing the scope so the object get recreated every pass solved the problem. Why because there is some sort of pointer to the original object and it hasn't been updated even though every property on it was reassigned???
private void MyMethod()
{
foreach (ReservedSimProjects item in parameters.ReservedProjects.ReservedSimProj)
{
SomeObj ProjDtl = new SomeObj(); //here is the obj method scoped
IQueryable<SJ> DbProj = SimColl.Where(e => e.SimProjectID == item.ProjectId);
ProjDtl.ProjName = DbProj.First().ProjName;
ProjDtl.ProjArea = DbProj.First().ProjArea;
ProjDtl.ProjPerim = DbProj.First().ProjArea;
....etc....
ProjectsDetails.Add(ProjDtl);
}
So for once I managed to solve my own problem but I'm not exactly sure why/what was solved.
JB
Upvotes: 1
Views: 928
Reputation: 50189
You can't reuse your object like that as it will try to save the same object multiple times.
You can reuse the variable, but not the object
private void MyMethod()
{
SomeObj ProjDtl = null;
foreach (ReservedSimProjects item in parameters.ReservedProjects.ReservedSimProj)
{
ProjDtl = new SomeObj()
IQueryable<SJ> DbProj = SimColl.Where(e => e.SimProjectID == item.ProjectId);
ProjDtl.ProjName = DbProj.First().ProjName;
ProjDtl.ProjArea = DbProj.First().ProjArea;
ProjDtl.ProjPerim = DbProj.First().ProjArea;
....etc....
ProjectsDetails.Add(ProjDtl);
}
Upvotes: 1
Reputation: 15974
When you create an object using new
, some space in memory is reserved for it. The variable you use to access the object doesn't store the object directly, but rather a pointer to the objects location.
SomeObj ProjDtl = new SomeObj();
RAM:
+--------------------+-----------------------------+
| 0x12345 | 0xabcdef |
+--------------------+-----------------------------+
| ProjDtl = 0xabcdef | [data for a SomeObj object] |
+--------------------+-----------------------------+
In your original loop, you had multiple variables, but each one pointed to the same address in memory and used the same actual object:
SomeObj ProjDtl = new SomeObj(); //now ProjDtl points to 0xabcdef
foreach (ReservedSimProjects item in parameters.ReservedProjects.ReservedSimProj)
{
IQueryable<SJ> DbProj = SimColl.Where(e => e.SimProjectID == item.ProjectId);
ProjDtl.ProjName = DbProj.First().ProjName; //Since ProjDtl is never overwritten,
ProjDtl.ProjArea = DbProj.First().ProjArea; //it will always point to 0xabcdef,
ProjDtl.ProjPerim = DbProj.First().ProjArea; //and you're always accessing the same physical object's data
....etc....
ProjectsDetails.Add(ProjDtl);
}
In your corrected version, every time you create a new object inside the loop, you're setting aside more space in memory for a new object and modifying its details instead.
private void MyMethod()
{
foreach (ReservedSimProjects item in parameters.ReservedProjects.ReservedSimProj)
{
SomeObj ProjDtl = new SomeObj(); //On the first iteration, ProjDtl might point to 0xabcdef,
//on the second, 0x98765, on the third, 0xfedcba... but it will always be a new, unused memory address
IQueryable<SJ> DbProj = SimColl.Where(e => e.SimProjectID == item.ProjectId);
ProjDtl.ProjName = DbProj.First().ProjName; //Now, each iteration modifies a different
ProjDtl.ProjArea = DbProj.First().ProjArea; //physical object
ProjDtl.ProjPerim = DbProj.First().ProjArea;
....etc....
ProjectsDetails.Add(ProjDtl);
}
Upvotes: 4
Reputation: 152566
Why because there is some sort of pointer to the original object and it hasn't been updated even though every property on it was reassigned???
Yes - non-primitive and non-struct types are "reference types" - meaning when you create a variable of that type you are creating a refrence (pointer) to that instance, so reassigning the values within the loop is really affecting the same instance each time.
Your solution is the correct one.
Upvotes: 0
Reputation: 24383
Why because there is some sort of pointer to the original object and it hasn't been updated even though every property on it was reassigned???
That's right.
You've created one object. You can set all the properties on that one object as many times as you like, but it is still the same object.
Each time you call ProjectDetails.Add(ProjDtl)
, you are adding the same object to the list.
The list doesn't store the values of the object's properties - it stores a single reference to the object itself.
Your fixed example works because you are creating a new object each time around the loop. Then you set the properties of that particular object and add it to the list.
This means the list ends up holding references to lots of different objects, each with their own property values.
Upvotes: 3
Reputation: 77556
Yes, that "pointer to the original object" is in fact your variable. ProjectsDetails.Add
adds the reference to that object to your list on each iteration. But since it's the same variable, it's the same object! So all you are doing is overwriting the properties of that one instance over and over again in your loop. If your list is N values long, then you will have a list of N items all pointing to the same instance.
Upvotes: 1