How to manually create a deep copy - c#

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.

Related

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.

Application variable always references my object, I want it to keep a "copy"

maybe its been a long day, but I just cant figure this out.
I retrieve a large custom object from WCF, and store it in an application variable.
This happens every 20 minutes.
For each web user, I am checking the existence and timeout of this application variable, and if needed, re-query my wcf and build a new object, and re-store it in the application variable.
This all good and well.
Now, I am trying to "make a copy" of this "master" object, modify it, and store it in a session variable, modifying it as needed throughout the session life cycle. (modifying the session variable).
Everytime I modify the session object, the object in the application variable gets modified.
Pseudo
application("mastervar") = object from wcf (obejct type - xcustomclass)
dim mynewobject as new xcustomclass
mynewobject = application("mastervar")
* Modifying mynewobject, also modifies application("mastervar")
I have tried:
session("mynewSessionVar") = application("mastervar")
mynewobject = session("mynewSessionVar")
Modifying mynewobject, modifies application("mastervar")
I have tried:
Manually copying all properties in mastervar object to new object, with a for loop.
mycustomobject = new xcustomclass
mycustomobjectObject as new xcustomclass.object
mymasterobject = application("mastervar")
for each object in mymasterobject.objectslist
mycustomobjectObject = new xcustomclass.object
with mycustomobjectObject
.property = object.property
end with
mycustomobject.objectlist.add(mycustomobjectObject)
next
Same thing, modifying mycustomobject, also modifies application("mastervar")
As I said, maybe its been a long day, but I've been bumping my head against this for hours...
EDIT
Private Function copy_fresh_units(unitsFromWcf As WebResortUnits) As WebResortUnits
Dim myFreshUnits As New WebResortUnits
Dim myFreshUnit As WebResortUnits.qbunit
For Each Unit In unitsFromWcf.resortUnits
myFreshUnit = New WebResortUnits.qbunit
With myFreshUnit
' .Availability = Unit.Availability
.mapDetails = Unit.mapDetails
End With
myFreshUnits.resortUnits.Add(Unit)
Next
return myFreshUnits
End Function
Modifying the availability property in myfreshUnits, it still updates the app var. I have had a look at reference and value types, and it is definitely my issue. But taking this alst edit into account, I know I am missing something, what it is, I am not sure... :-)
You are creating a new reference to the objects and then modifying the object that you reference and expecting your two references to not be the same object?
It sounds like what you really want to do is to clone the objects or make a deepcopy of the objects.
If these are custom objects you will need custom code to make a Clone of them.
When you Clone your object be sure that you create a new object and set all of the value types on that new object from your old object. Then go through and clone all of your reference types and set the reference properties on your clone to point to the clones of the properties you've created.
EDIT: To address your update
The problem is still... everything you are copying is obviously a reference type and it's not being cloned. So there is only one object in existence therefor when you edit either reference it changes the object.
EDIT 2: Serialization will help you
Serializing and deserializing your base object in memory is an easy way to clone it. I generally write a custom clone method that serializes / deserializes the object. That way you have a Clone() method that you will always call and any custom code you need that doesn't get handled properly with serialize / deserialize you can handle in that method.
My guess is that the properties you are copying are not all primitives themselves (int, float, string, etc). When you then alter the corresponding property on the new object, it is then altering the original property (since it's not a primitive and is really an object reference).
Check out https://github.com/JesseBuesking/BB.DeepCopy which is probably a bit of overkill, but if you read what's under The problem this addresses you can see alternative approaches for helping in this situation.

Full copy small List to Container List, not only reference

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)

Downcasting in C#

I'm facing a problem that I don't know how to solve and am hoping the community can help.
I'm writing an app that manages "Lead" objects. (These are sales leads.) One part of my program will import leads from a text file. Now, the text file contains lots of potential leads, some of which I will want to import and some of which I won't.
For ease of programming (and use), I'm parsing the text file into a List<Lead> object, and using a DataGridView to display the leads by setting the DataSource property of the DataGridView.
What I want to do is add a column to the grid, called "Import," with a checkbox that the user can check to indicate whether or not each lead should be imported.
My first thought is to derive a class from Lead:
public Class LeadWithImportCheckbox : Lead
{
bool bImport = false;
public bool Import
{
get { return bImport;}
set { bImport = value;}
}
}
However, the parsing engine returns a list of Lead objects. I can't downcast a Lead to a LeadWithImportCheckbox. This fails:
LeadWithImportCheckbox newLead = (LeadWithImportCheckbox)LeadFromParsingEngine;
This is an invalid cast.
The other option I see is to create a constructor for LeadWithImportCheckbox:
public LeadWithImportCheckbox(Lead newlead)
{
base.Property1 = newlead.Property1;
base.Property2 = newlead.Property2;
....
base.Property_n = newlead.Property_n;
}
This is problematic for two reasons. One, the Lead object has several dozen properties and writing this constructor is a PITA.
But worse, if I ever change the underlying structure of Lead, I need to remember to go back and change this constructor for LeadWithImportCheckbox. This is a danger to my code maintenance.
Is there a better way of accomplishing my goal?
or, to avoid the PITA aspect, use reflection... (try this...)
EDIT: use property, not Field as I had originally written...
public class NewLead : Lead
{
public bool Insert;
public NewLead(Lead lead, bool insert)
{
Insert = insert;
foreach (PropertyInfo pi in typeof(Lead).GetProperties())
GetType().GetProperty(pi.Name).SetValue
(this, pi.GetValue(lead,null), null);
}
}
public class LeadListItem
{
public Lead Lead { get; set; }
public bool ShouldImport { get; set; }
}
i.e. don't copy the Lead object's contents, just store a reference to it in a new LeadListItem object, which adds extra info "outside" the original object.
If you want the properties of Lead to appear in the grid, there is almost certainly a way of doing that. Why not ask that question, instead of downvoting me for telling you the right answer to this question!
A couple options you might have missed:
You could update the Lead object itself to have an Import property (that defaults to false).
You could have your "ImportLead" object treat the Lead as payload (even make it generic, if you want), so you don't need the big constructor.
Build a new Lead object list or enumerable that only contains the objects you want to import in the first place.
You can only downcast, if the object to be downcast is really an object of that type.
An easier way to solve your problem would be to have a DisplayLead class, such as:
public class DisplayLead {
Lead lead;
bool bImport;
}
which would also help you separating stored data from their representation in a GUI.
What you want to do is display the checkbox column on your grid and not have it related at all to your Lead objects. You use the marked columns (and possible the original List) to build a new set of List which will be your import list.
Then handle whatever you wish to do with the newly created List.
Edit: One thing to be careful of when working with lists is the fact every class object is actually only a pointer to the class so if you work with the original list and do something like:
List<Lead> Importable = new List<Lead>();
for(int i=0, i++, i<viewGrid.Count)
if(viewGrid[i].CheckedColumn.Checked)
Importable.Add(OriginalList[i]);
That objects will exist in both lists and if you edit data of a Lead on either list both will be changed.
I cannot downcast to something it is not. If the object was instantiated as a Lead, then it can't be downcast to any derived class. If it were instantiated as a LeadWithImportCheckbox and then returned to your code as Lead, then you can downcast it.
Protip: Check type at runtime with is operator.
There are many ways to do this, but the "right" way pops out because of what you said, here:
For ease of programming (and use), I'm
parsing the text file into a
List object, and using a
DataGridView to display the leads by
setting the DataSource property of the
DataGridView.
What I want to do is add a column to
the grid, called "Import," with a
checkbox that the user can check to
indicate whether or not each lead
should be imported.
Your Lead object stands well on its own, and you want to attach some metadata to it -- you don't want to create another Lead classification (i.e. the LeadWithImportCheckbox class).
So, the best approach in your case is to have a class like so:
public class LeadInfo
{
private Lead lead;
private bool shouldImport;
public LeadInfo(Lead lead)
{
this.lead = lead;
this.ShouldImport = false;
}
public bool ShouldImport
{
get { return shouldImport; }
set { shouldImport = value; }
}
}
This will scale well when you want to add more metadata to your list, like if you want to send yourself email reminders about them every week.
I've seen the correct solution listed so many times I feel like a heel posting it again, but the best way to approach this is to write a wrapper for the Lead object that includes the import flag.
If the properties of the Lead object don't appear in the GridView because you're databinding to the object, then write passthrough properties that mirror the Lead properties on the wrapper object.
The issue is that you want something displayed to the user that isn't an inherent part of the data model. The answer is to wrap the data before presenting it to the user so you can control what they see without changing the underlying model.
If you're concerned that the Lead object will change so many times in the future that changes to the wrapper will be cumbersome, you could look into dynamic code generation based on the Lead object that will automatically generate a wrapper object with the same fields as the Lead object plus the import flag. Though frankly, that's a lot more work than you'll probably need for something as straightforward as this.
As a quick and dirty solution, you can create your 'checkbox' object as a different object that contains an instance of Lead.
public GridLead {
public bool Import { get; set; }
public Lead Lead { get; set; }
}
This way you can easily add more 'grid' properties to this object, while still always retaining a reference to the Lead details without hardcoding property cloning into it.
Recommend you try modifying (upgrading) your imported lead objects.
Try starting with the examples here...
If your Lead class had a copy constructor (e.g. "Lead(Lead otherLead)"), LeadWithImportCheckbox would inherit that and you could just call the base Lead constructor in the LeadWithImportCheckbox constructor - hence no need for LeadWithImportCheckbox to be aware of the details of Lead.

Categories

Resources