In a loop, is to create new object is so necessary? - c#

var users = new List<User>();
User user = new User();
foreach (var element in elements)
{
try
{
user.Id = element.Attribute("Id").Value;
user.Reputation = element.Attribute("Reputation").Value;
user.CreationDate = DateTime.Parse(element.Attribute("CreationDate").Value);
user.DisplayName = element.Attribute("DisplayName").Value;
user.LastAccessDate = Convert.ToDateTime(element.Attribute("LastAccessDate").Value);
user.WebsiteUrl = element.Attribute("WebsiteUrl").Value;
user.Location = element.Attribute("Location").Value;
user.Age = Convert.ToInt32(element.Attribute("Age").Value);
user.AboutMe = element.Attribute("AboutMe").Value;
user.Views = element.Attribute("Views").Value.ToInt32();
user.UpVotes = element.Attribute("UpVotes").Value.ToInt32();
user.DownVotes = element.Attribute("DownVotes").Value.ToInt32();
users.Add(user);
}
catch (NullReferenceException)
{
// do nothing
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
}
}
The expression User user = new User(); is used outside the foreach loop. My intention is to avoid instantiating new User object, if a loop runs 10000000 time (suppose), what if I just instantiate a single time and on each loop I just change its contents variable and adding to the a list. But what happen... I although get all different users, but in my final list there is only one user (the first user) and it has as many copies as loop runs...
The problem can be solved the taking the express User user = new User(); in foreach loop, but I'm not convinced by myself, why it need to instantiate a new object on each loop ?..... Please clear me

When you add it to the list, you adding a reference to the object you are creating and the list is keeping it for future use.
By putting the "new" inside the loop, you are adding a new object each time. You get a performance hit because you are allocating memory for it. There are ways to mitigate this so the hit is somewhere else (i.e. a pool/list of them created when your program starts up that you use when the program runs), but you must allocate them somewhere.
By not putting a "new" inside the loop, every element of the list points back to the same single object you created.
If you want to keep different information for each object, it must be stored somewhere.
This concept is NOT just for C#.

Reference types and value types are different.This is because every time in the foreach loop you just changing one User and add it to your list.
Value types: A data type is a value type if it holds the data within its own memory allocation.
Reference types: A reference type contains a pointer to another memory location that holds the data.
Check this for more details: http://msdn.microsoft.com/en-us/library/t63sy5hs.aspx
As the others said you should move your User definition inside of your foreach loop:
foreach (var element in elements)
{
User user = new User();
...
}

Related

Can I make a Session variable that behaves like a vector/list?

So, I'm using C# and I really need to store in a Session variable multiple data. I can't define as many Session variables as I need because I the number could be infinite.
I need to store everything in a Session, then loop through it. Is it possible?
So: I have a page with products, the Client can ADD to the basket as many items as he wants (all of this occurrs on the same page).
You can iterate over all keys or store a list of elements using one key "basket" (or "cart"):
IList<CartItem> GetCartLines()
{
return Session["Basket"] as List<CartItem>;
}
void AddToCart(CartItem item)
{
var cartLines = Session["Basket"] as List<CartItem>;
if(cartLines==null)
Session["Basket"] = cartLines = new List<CartItem>();
cartLines.Add(item);
}

What if I never create new object but keep adding the old object into the List by just updating it's value

In a for loop, instead of declaring a new object and add it to my List, I just update the value of the old object and every time keep adding this old object to my List, why after a few loops all List elements become the same
foreach (vg_ts_VesselCashflow_CashFlow_Entity item in cashflow)
{
var result = new VslMonthlyCashflow_Record();
result.CapitalCost = item.CapitalCost;
result.CharterRevenue = item.CharterRevenue;
result.Date = item.Period;
result.DryDock = item.DryDock;
resultList.Add(result);
}
if (resultList != null)
return resultList;
//Compared with this:
var result = new VslMonthlyCashflow_Record();
foreach (vg_ts_VesselCashflow_CashFlow_Entity item in cashflow)
{
result.CapitalCost = item.CapitalCost;
result.CharterRevenue = item.CharterRevenue;
result.Date = item.Period;
result.DryDock = item.DryDock;
resultList.Add(result);
}
I expect my resultList to be updated but if I keep using the old object, when it loops 123 times, all elements in the List will be the same.
List#Add doesn't copy the object or anything like that, it just keeps a reference to the object you passed to it. In the second snippet, you keep adding the same object to the list multiple times. Each modification you perform on the object is visible through all the references pointing to it, including the local result variable and all the elements of the list.

How to get the value of a variable to a string?

I am trying to add a item to my listView. The listView populates but I am getting this:
Systems.Collection.Generic.List'1[System.String]
This is the code I am trying to use:
foreach (SearchResult entry in result)
{
var members = GetGroupMemberList(entry.GetDirectoryEntry());
var item = members;
itmListItem = new ListViewItem((string)entry.Properties["sAMAccountName"][0]);
itmListItem.SubItems.Add(item.ToString());
lvwListView.Items.Add(itmListItem);
lvwListView.Refresh();
itmListItem = null;
}
Thanks
The problem you're running into is that item is not a string: it's a List<string>, so calling ToString() on it doesn't show you anything more meaningful than its type. Often people really want to get something like a comma-separated list of items to show, which could be accomplished by saying string.Join(", ", members).
But I'm reading the tea leaves here and thinking you probably really want each item in the members to show up as a sub-item in your list, which you could accomplish like this:
foreach (SearchResult entry in result)
{
var members = GetGroupMemberList(entry.GetDirectoryEntry());
foreach(var item in members)
{
var itmListItem = new ListViewItem((string)entry.Properties["sAMAccountName"][0]);
itmListItem.SubItems.Add(item.ToString());
lvwListView.Items.Add(itmListItem);
}
lvwListView.Refresh();
}
Note that I'm declaring itmListItem closer to where you actually use it, which makes it unnecessary to set it to null later. It's generally good practice to declare variables closer to their usage, and in as small as scope as possible.

ViewModel returns same values for all 500+ records to the view

I am new to using ViewModels, I have a new list here and am adding items to it by looping though a database table. The issue is that all the records that come back are identical using the same record over and over. What could be the issue and is this a good way to accomplish filling with data and Passing a ViewModel or is there a better way? Right now it returns about 500 records with the same data.
public class DimCustomersController : Controller
{
private AdventureWorks_MBDEV_DW2008Entities db = new AdventureWorks_MBDEV_DW2008Entities();
public ActionResult CustomersIndexVM()
{
List<DimCustomersIndexViewModel> CustomerList = new List<DimCustomersIndexViewModel>();
DimCustomersIndexViewModel CustomerItem = new DimCustomersIndexViewModel();
foreach (var m in db.DimCustomers.ToList())// cold do for loop up to count
{
CustomerItem.Title = m.Title;
CustomerItem.FirstName = m.FirstName;
CustomerItem.MiddleName = m.MiddleName;
CustomerItem.LastName = m.LastName;
CustomerItem.BirthDate = m.BirthDate;
CustomerItem.MaritalStatus = m.MaritalStatus;
CustomerItem.Suffix = m.Suffix;
CustomerItem.Gender = m.Gender;
CustomerItem.EmailAddress = m.EmailAddress;
CustomerItem.AddressLine1 = m.AddressLine1;
CustomerItem.AddressLine2 = m.AddressLine2;
CustomerItem.Phone = m.Phone;
//other columns go here
CustomerList.Add(CustomerItem);
}
return View("CustomersIndexVM", CustomerList);
}
This line needs to be inside the loop:
DimCustomersIndexViewModel CustomerItem = new DimCustomersIndexViewModel();
The reason is that you want a new view model for each customer, but instead you are currently creating only one view model and changing its properties. When you add it to the list, you are not adding a copy; you are adding the same view model you already added.
This code would work if DimCustomersIndexViewModel was a struct, because structs are just a bag of values that have no inherent identity and they are copied rather than referenced. (Technical comparison.) But it's a class (as it should be), with a unique identity, so you're adding a reference to the single view model into the list over and over. Customerlist[0] and CustomerList[1] and all the other items point to the same DimCustomersIndexViewModel object instance, whose properties are then overwritten and left equal to the very last customer.
By moving this line inside the loop, you are creating a separate DimCustomersIndexViewModel for each customer, each with its own set of properties, and CustomerList contains references to many different DimCustomersIndexViewModel object instances.
Once you have solid experience with this concept, a future step could be to use AutoMapper so that you don't have to maintain a list of all properties in your code here.
The problem is you add the same reference object during each iteration of your loop. That object never changes (you never new it up again), but you change the properties on the object. Then you add that object over and over. You need to new up that object each iteration of the loop.

Why does the Foreach doesn't impact?

The code below doing a simple thing. manipulate the API's raw data and bind it to the view model's property.
I fetch data from a web service and save it to a object named calljsonObject. This is the raw data. Then I do a foreach loop to select the selected data from the raw data, and save it to a object named tmpList, and at the last line, bind tmpList to the view model property named docList
SingleBoardListRawData calljsonObject = JsonConvert.DeserializeObject<SingleBoardListRawData>(callbackjsonstring);
ObservableCollection<SinglePostViewModel> tmpList = new ObservableCollection<SinglePostViewModel>();
SinglePostViewModel tmpPost = new SinglePostViewModel();
foreach (List<object> item in calljsonObject.data)
{
tmpPost.doc_id = (long)item[0];
tmpPost.doc_title = (string)item[1];
tmpPost.doc_author = (string)item[2];
tmpPost.repliesCount = (long)item[4];
tmpPost.doc_post_date = DateTime.Parse((string)item[5]);
tmpPost.OnTop = (long)item[6];
tmpPost.CoolPost = (long)item[7];
tmpPost.doc_update_date = DateTime.Parse((string)item[9]);
tmpPost.PicInDoc = (long)item[10];
tmpPost.reply_user_name = (string)item[11];
tmpPost.doc_brief = (string)item[13];
tmpList.Add(tmpPost);
}
this.docList = tmpList;
But the result is the tmpList full of the same data, which is the result of the last foreach manipulation. But I thought that I've re-assigned the tmpPost value, it seems every Add method will take place the previous one.
I don't want to new a object everytime I do a foreach loop, I think it cost a lot,
My Question is :
1. Why?
2. How to solve it?
You're adding a reference to the same object on each iteration, and overwriting the data within that object on each iteration. You need to create a new object on each iteration. Move this line:
SinglePostViewModel tmpPost = new SinglePostViewModel();
into the loop.
foreach (List<object> item in calljsonObject.data)
{
SinglePostViewModel tmpPost = new SinglePostViewModel();
tmpPost.doc_id = (long)item[0];
...
}
I don't want to new a object everytime I do a foreach loop, I think it cost a lot,
How do you expect to maintain the different values if you don't create that many objects? Where do you expect the data to live? And what evidence do you have for your performance concern?
It's very important that you understand how reference types and value types work. Please read my article on this topic and think about how that applies in your situation.
If we assume that SinglePostViewModel, then you are adding the same reference multiple times in the list. There is only one instance of the SinglePostViewModel - you are simply over-writing it each time, hence the fail.
I don't want to new a object everytime I do a foreach loop, I think it cost a lot
Unless you are talking 10s of millions of records, your concerns are very unlikely to be justified. The data needs to go somewhere, after all.
My Question is : 1. Why? 2. How to solve it?
because you only have one object that you keep over-writing
don't do that

Categories

Resources