I have List<string> I am passing from model to control and back again. My initial problem was that when I use List.remove() to remove an item from the list<> it is somehow coming back when passing it back to the View.
I decided to create a new list<>, put the model.List<> values in it, clear the Model.List<>, and then put the values from the tmp List<> back in the Model.List<>.
However, when I clear the Model.List<> the tmp List<> values are being cleared as well.
if (!string.IsNullOrEmpty(model.removeDate))
{
model.multipleSingleDay_Date.Remove(model.removeDate);
List<string> tmpV = new List<string>();
tmpV = model.multipleSingleDay_Date;
model.multipleSingleDay_Date.Clear();
model.multipleSingleDay_Date = tmpV;
}
You are using a reference to the original list.
To make a new list, use a new List<string>(); and iterate through your original list to fill the new one. This can be done in several ways.
tmpV = model.multipleSingleDay_Date;
All the above line does is say "the reference the variable model.multipleSingleDay_Date has should be used in the tmpV variable".
Loop through the original list and add each value to the new list. Or copy the list, see comments below.
Related
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.
I need to store two variables and then check if they have not changed.
List<CatalogInfo> list_catalogs = new List<CatalogInfo>();
List<FileInfo> list_files = new List<FileInfo>();
List<CatalogInfo> list_catalogs_for_check_changed = new List<CatalogInfo>();
List<FileInfo> list_files_check_changed = new List<FileInfo>();
When I do:
list_catalogs_for_check_changed = list_catalogs;
list_files_check_changed = list_files;
But When I add to list_catalogs or list_files Items I see in debager that Items add to list_catalogs_for_check_changed or list_files_check_changed. Why??? I don't add Items to with variables.
list_catalogs.Add(new CatalogInfo() { Action = "Create", Path = folderBrowserDialog1.SelectedPath });
When you do this:
list_catalogs_for_check_changed = list_catalogs;
You are not making a copy of the list, you are assigning a new reference to the same list. If you want to create a new list with the same items, do this:
list_catalogs_for_check_changed = new List<CatalogInfo>(list_catalogs);
This assigns a new List<CatalogInfo> and passes the list from which to copy the elements, resulting in two independent lists with the same items.
I don't add Items to with variables.
Indeed, you don't. You are adding items to the lists. If you do (from the question):
list_catalogs_for_check_changed = list_catalogs;
list_files_check_changed = list_files;
Then both list_catalogs_for_check_changed and list_catalogs hold a reference to the same list of CatalogInfo. Likewise, list_files and list_files_check_changed hold a reference to the same list of FileInfos. It therefore follows that if you add an item to that list, it will be visible via either variable.
The variable is not the list: the list is somewhere on the managed heap. The variable is just the reference to the list. Assigning one list variable to another copies the reference. It does not make a copy of the list.
When you do
list_catalogs_for_check_changed = list_catalogs;
You are handing over a reference to list_catalogs. You want to copy it.
This is an article describing value types vs reference
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
I have a List that receives ids. It is instantiated outside the foreach statement.
List<int> indices = new List<int>();
foreach (var m in docsRelacionadosModel)
{
//.. do stuff
modelTemp.indices = indices;
//..here I do more stuff and some time it goes to the next iteration and I need to keep the value in indices to get more values.
//although in a condition
if(isOk) {
//I save the value of this list to a model
model.indices = modelTemp.indices;
//And I need to clear the list to get new values
indices.Clear(); <--- This will clear the values saved in model.indices
}
}
As it has values passed by reference, how can I keep the values in model.indices?
You need to make a copy of the list and save that copy to model.indecies. While there are a number of ways of copying the list the LINQ ToList extension method is probably the most convenient:
model.indices = modelTemp.indices.ToList();
Another option is to just use the List constructor:
model.indices = new List<int>(modelTemp.indices);
Just create a copy of the list:
model.indices = new List<int>(modelTemp.indices);
As per this S/O question, the easiest way may be to call ToList on your list:
model.indices = modelTemp.indices.ToList();
You could also instantiate as a new list, passing your list as a constructor parameter.
I am trying to remove an object from an array and fill the slot with an object of the same type but with 0s for all the properties. But when I do this the values do not clear for some reason when I recalculate the array values.
Here is how I am clearing an object out and inserting a blank one in its place.
public void clearOutBox(int arraySlot)
{
itemsInbuildArray.Remove(itemsArray[arraySlot]);
itemsInbuildArray.Insert(arraySlot, blank);
itemInBuildPictureArray[arraySlot].ImageLocation = null;
statCalculation();
}
//one of the lines from the statCalculation method.
statsHealth.Text = (Convert.ToString(itemsInbuildArray.Sum(hp => hp.Health)));
public partial class Form1 : Form
{
List<Item> itemsArray = new List<Item>();
List<PictureBox> itemInBuildPictureArray = new List<PictureBox>();
List<ToolTip> itemInBuildTooltipArray = new List<ToolTip>();
List<Item> itemsInbuildArray = new List<Item>();
Item blank = new Item(); // this is one of several objects created here
}
I initialize the array with 6 of these blank items in it and there are no problems replacing a blank item with one with values but removing it is whats causing me issues.
Please excuse the more than likely noobish ways I'm doing this, I am just starting C# and doing this project as a learning experience. Any input is appreciated!
Why not just index it directly:
int index = 5;
array[index] = new Foobar(); // whatever your class is
That is going to change whatever is referenced in the 6th slot in your array.
I would avoid using a single reference called "blank" and putting it into multiple array slots unless you know you will never modify them. If they are reference types then modifying one of them would modify them all.