Full copy small List to Container List, not only reference - c#

I was hoping the new keyword, would not only create a new object, but also with unique memory references. If I do this, and after Clear the "tinyList", the bigList will also be cleared.
bigList.Add(new bigListObject(tinyList));
bigList is a List and Construcotr looks like
public Foo(List<SmallClass> in)
{
_test = new List<SmallClass>();
_test = in;
}
This works, but how can I clear the tinyList, fill it, and continue adding to bigList?
The whole idea is to have a big list and one small for adding.. Now I have two lists from two different classes, almost the same.
Thanks

You can copy the references to a new list:
public Foo(List<SmallClass> in)
{
_test = new List<SmallClass>(in);
}
now _test and in point to two different lists, so removing an object from one list does not affect the other.
However, they are the same references. So editing one of the SmallClass instances in list in will affect the corresponding instance in list _test because the references point to the same instances.
If you need copies of the SmallClass instances then you'll need to implement a copy method (or use object.MemberwiseClone)

Related

Preventing list items from being edited after assigned to the list

So I'm trying to make a list that consist of different versions of a local variable that keeps changing every loop. However, after the loop is done all the values are the same as the most recent one because they update along with the given value as opposed to staying the same value when I assigned them. There is probably a pretty simple solution to this problem but I have not been able to find it through trial and error. Here a little example of what I am trying to do:
List<Item> itemList = new List<Item>();
Item itemA = new Item;
while(repeating condition)
{
itemList.Add(itemA)
// *itemA changes*
}
So I want itemList to have a new entry every loop that does not change along with itemA after being added.
Because you never actually change out (for a whole new object) the object that your itemA is pointing to in memory, all you end up with is a list of e.g. 100 entries that are all just pointing to the same sole instance of ItemA in memory
In terms you might be more familiar with, your new ItemA() data is like having a text file on disk somewhere and itemA is a shortcut to it. Calling list.Add(itemA) (or associating another variable like var itemA2 = itemA) is merely creating another shortcut to the same file, it is not copying the file to another file.
If you double click your itemA shortcut to open the file in notepad, edit the contents, save it, close it, then doubleclick itemA2 shortcut then you wouldnt be surprised to see that notepad opens showing a file that has your changes
This is what C# does when you make objects
var myShortcut1 = new RealDataSomewhere();
var myShortcut2 = myShortcut1; //not a copy, another shortcut to the same realdata
var myArrayOfShortcuts = new [] { myShortcut1, myShortcut1, myShortcut1, myShortcut1, myShortcut1}; //every array index is also a shortcut
//at this point there is still only one RealDataSomewhere object in memory and now 7 shortcuts to it
Either clone your itemA before/after you do things to it, adding the clode to the list, or make a new itemA on every pass of the loop. Which of these you actually do depends on what the rest of the code (we can't see) does with itemA
There is a long discussion about cloning here including several handy suggestions for deep cloning,
Since itemA is a reference type, your list contains a bunch of copies of a reference to an Item. In the comment where it says \\ itemA changes, the code is most likely only changing properties of the Item that itemA refers to:
List<Item> itemList = new List<Item>();
var itemA = new Item { SomeProperty = someValue };
while(repeating condition)
{
itemList.Add(itemA)
// itemA changes (but not really - we only change the instance it refers to)
itemA.SomeProperty = newValue;
}
So all that's really happening is that the object that itemA refers to is changing, but itemA is technically still the same - it's still pointing to the same object in memory.
To resolve the issue, we need to reassign itemA to a new instance of Item rather than just modifying the instance it refers to. In the sample code you provided (which is a little sparse - you should include the code that "changes" itemA) it might look like:
List<Item> itemList = new List<Item>();
Item itemA = new Item { SomeProperty = someValue };
while(repeating condition)
{
itemList.Add(itemA)
// Now itemA *does* change - we set it to refer to a *new* instance of Item
itemA = new Item { SomeProperty = newValue };
}
Class are reference type as List does. C# List strores refrences of class instances in List. If you change the variable the List item which is references to that item will refer to that changed item. So if your variable changes and you don't want to refelect that change to your List you must make deep copy of your variable and then added to List. you can do this y the way introduced here.
What you are doing is saving a reference to itemA, so list ends up being a bunch of variables that all point to the same data. What you need to do is copy the object and save the copy.
Try replacing itemList.Add(itemA) with itemList.Add(itemA.Clone()).
You will have to write the Clone() method yourself, and the implementation is up to you. It could be a constructor that takes an item as a parameter and copies it's values or a method that returns a clone of the object it was called on.
See Caius Jard's answer for a link to more discussion on cloning.

in c#, Why this code work as by reference? I intended to use as by value

I'm trying to make a list of class as history.
So list of a class was declared like this.
private List<SearchHistoryItem> SearchHistoryList;
SearchHistoryItem is a class that have two property.
public DataTable SearchResultDataTable;
public SearchCondition SearchCondition; // this is another class.
Whenever this method is called, I make temporary 'SearchHistoryItem', copy from current instance and add to the list.
public void GetMainDataAsConditionMethod()
{
SearchHistoryItem tmpItem = new SearchHistoryItem();
tmpItem.SearchCondition = CurrentSearchCondition;
tmpItem.SearchResultDataTable = MainChartDataTable;
SearchHistoryList.Add(tmpItem);
}
I think there is no reason to copy datas by reference. But when this code is running,
every items in the List 'SearchHistoryList' have same values of CurrentSearchCondition and MainChartDataTable.
I checked
How can I solve this to be copied by value?
When you assign an object (such as a List) to a variable, you assign a reference. When you do anything to the object on one reference, all references will show the change, because they are just references to the same object.
What you want to do is copying the list before you pass it on, such as
tmpItem.SearchResultDataTable = new List<...>();
tmpItem.SearchResultDataTable.AddRange(MainChartDataTable);
Note: This only creates a shallow copy, not a deep copy. If you want a deep copy, would have to clone each object in the list individually.

Create a copy of an ObservableCollection that doesn't update

I am building a control in xamarin forms that binds to a list of objects. To get this binding to work I need to use observable collections (otherwise propertychanged methods don't fire).
I noticed a really frustrating interaction as a result of needing to use OC's as opposed to lists. Whenever the binded OC updates, the values in my controls are automatically updated, even if they are just references of the OC, Here is how i am copying the OC.
//Internal list of events
private List<EventItem> _events;
void OnEventsChanged(ObservableCollection<EventItem> eventsCollection)
{
//Error handle
List<EventItem> events = eventsCollection.ToList();
//Do something
_events = events;
}
The problem comes when the OC updates, I want to check for new/deleted AND altered objects. The issue is that when the OC updates, it is updating the internal list (_events) aswell. This means when I go to do comparisons between the old & new values, they are the same.
Honestly I don't really understand how c# handles copying references of objects around, I had a similar issue a while back with DateTime.Now being calculated as opposed to copying the value of the already initialised object.
var time = DateTime.Now;
await Task.Delay(1000);
var time2 = time; //This is 1 second later than time, not the value of time (which is what I wanted)
I have used Objective-C in the past and that has the concept of MutableCopy where you can assign a new list from an existing one, they have the same values but aren't linked.
How can I do this in C# so that my controls internal list is only updated by me and not the OC?
Thanks
That's perfectly normal. If I have enough time, I'll try to explain it to you.
In a nutshell, the observableList (or a List) is a list of reference to the objects and not a list of objects. The thing is that the objects are not copied inside a list but the list contains a reference to the different objects. That means that if you do something like ToList(), you get another list of references to the exact same objects.
Now to solve your problem. Just create a new list with new objects with something like
var newList = oldList.Select(x => new Model(x)).ToList();
And of course the Model class has a constructor that accept a Model as a parameter and copy the properties.
When you write _events = events;, you create not a new object, but a reference for the same object. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/index .
You should to clone (create a copy of object itself) as it mentioned in comment by #Matt.

Object in List not deleting on re opening the app

In my app, I store objects(of Class1) on two lists (of type List<Class1>).
The first list is used to store all the objects added in the app while the other list filters few of the objects based on a filtering function.
Both the lists are part of a class file(Class2) which I store in the app data using IsolatedStorage.ApplicationSettings .
When I access an object in the app, the object is extracted from the list and on changing any of its property, I click on a 'done' button.
done_event
{
remove the object from the first list;
remove it from the second list based on a simple condition (#2);
change its properties;
add the new object back to the first list;
run the filtering function to add the new object to the second list if necessary;
}
Everything works fine when I am using it after installing it on the emulator/device but once I exit the app and open it back again and change a property of an object, the new object is removed and added in the first list, however, it is not removed from the second list (the second list populates with two objects instead of one, I used breakpoints and figured out the object was not getting removed from the second list at step #2).
I am new to using IsolatedStorage, so don't know the drawbacks. Please help
I don't know how you load the objects of the two lists after a restart of the app, but maybe the ApplicationSettings deserializes your objects two times for the two lists so you have two different objects.
Try something like a proxy for the ApplicationSettings like the following example to keep only one valid list of all stored Class1-instances:
public List<Class1> Class1List
{
get
{
if(this.class1List == null)
{
if(this.applicationSettings.Contains("class1Key"))
this.class1List = (List<Class1>)this.applicationSettings["class1Key"];
}
return this.class1List;
}
set
{
this.applicationSettings["class1Key"] = value;
this.applicationSettings.Save();
}
}

How to manually create a deep copy

Following this site: http://www.csharp411.com/c-object-clone-wars/
I decided to manually create a deep copy of my class (following site 1. Clone Manually). I implemented the clone interface and any necessary properties. I executed my program and checked if my clone was indeed equal too the original instance. This was correct.
However, my new instance still referenced to the original one. So any changes in my copy where reflected into the original instance.
So if this doesn't create a deep copy, then what does? What could have gone wrong?
(I want to make a deep copy manually to increase my performance, so I do not want to use the ObjectCopier class. (even if it works great, it takes 90% of my code run time).
Code Snippets:
Class implements:
public class SudokuAlgorithmNorvig: ICloneable
{
Clone method:
public object Clone()
{
SudokuAlgorithmNorvig sudokuClone = new SudokuAlgorithmNorvig(this.BlockRows, this.BlockColumns);
sudokuClone.IsSucces = this.IsSucces;
if (this.Grid != null) sudokuClone.Grid = (Field[,])this.Grid;
if (this.Peers != null) sudokuClone.Peers = (Hashtable)this.Peers;
if (this.Units != null) sudokuClone.Units = (Hashtable)this.Units;
return sudokuClone;
}
Clone method call:
SudokuAlgorithmNorvig sudokuCopy = (SudokuAlgorithmNorvig)sudoku.Clone()
I did the same (implementing and setting clone method) in all my other classes. (Field + Coordinate)
It looks like you're creating references to existing objects all over the place instead of creating copies.
Are BlockRows and BlockColumns custom objects that you're passing into the new object? Those will just be references to BlockRows and BlockColumns in the existing object, so changing one of those instances in the first object will be reflected in the second.
I don't know what Grid, Peers, and Units represent, but those will most likely be references too. You need to make all those classes cloneable as well. Otherwise, changing Grid in the first instance of your SudokuAlgorithmNorvig class will change the corresponding Grid in the second instance.

Categories

Resources