Duplicate an ObservableCollection Item - c#

I want to duplicate a list item in an observablecollection. When I do:
TreasureCards[TreasureCards.Count - 1] = TreasureCards[CardPosition];
It creates a copy of the specific list item but then they are linked in my UI. So if I change the new duplicated item's name, it changes the originals name. I know I could do each of the properties one by one (see below) but is there a way to just copy the entire item?
TreasureCards[TreasureCards.Count - 1].Name = TreasurecCards[CardPosition].Name;
TreasureCards[TreasureCards.Count - 1].Type= TreasurecCards[CardPosition].Type;
// etc

You aren't duplicating the object. You're creating a new reference to the object. There's still only one object; now there are two references to it in your collection, and any change to the object is reflected by both references.
To create a new object, you can call MemberwiseClone() on anything that derives from Object. This method returns a new instance, copying the values from all fields in the original object. So you'd do:
TreasureCards[TreasureCards.Count - 1] = TreasureCards[CardPosition].MemberwiseClone();
There are two limitations with this method. First, it's a shallow copy, i.e. any reference fields in the original object have their values copied. So if a.Foo is a reference to a Bar object, a.MemberwiseClone().Foo will refer to the same Bar object. Second, the method just copies the fields; it doesn't call the new object's constructor. Depending on the design of the class, this is either unimportant or a Really Big Deal.
Usually, it's safer to make the class implement ICloneable and explicitly implement a Clone() method, e.g.:
public TreasureCard Clone()
{
return new TreasureCard
{
Name = this.Name,
Type = this.Type,
...
};
}

They aren't linked, they are the same instance. All you're doing is copying a reference to the same data to another position in the array.
What you need to do is implement some Clone method that makes a copy of the original instance but as another instance. This SO post might help.
Then you would do something like this:
TreasureCards[TreasureCards.Count - 1] = TreasureCards[CardPosition].Clone();

Related

How the Object Modification works?

I have two objects say Object1,Object2.
The two objects have the same properties.
My code is like below
Object1.property1=Object2.property1; // Object2.property1=**x**
Object2.property1= **y**;
When I try to retrieve the Object1.property1 it is displaying y.
Here I Don't want to change the Object1.property1 but it is Getting Modified when Object2.property1 has changed.
My Questions is
Why my code is behaving like that or Is there any concept that i don't know in c# ?
It is behaving like that because you don't actually have 2 objects. You only have one.
Object1 and Object2 are simply variables. They are not objects themselves. They store a "reference" that points to the object. You can use the variables to access the object. In some point in your code, you most probably have written
Object1 = Object2;
or
Object2 = Object1;
This makes the two variables hold 2 references that refers to the same object. When you edit the object by accessing through the variable Object1, you can see the effect by accessing the object through Object2. Because they are the same object.
Fore more details you read concept of : Deep Copy vs Shollow Copy
if you want to change that behavior than you need to make use of cloning/copy , right now you are assigning reference and that's why its changing in both the object ,
as property is byte array then you can do like this ,Array.CopyTo Method (Array, Int32)
Array1.CopyTo(Array2, 0);//
so in your case its like
Object2.property1.CopyTo(Object1.property1,0);
Object2.property1= **y**;
You might have to have a look at this Microsoft doc. The concept of value and reference types variables is a very basic and very important concept of c#.
Simply said: if you crate an object like this:
object2 = object1;
You dont really create a new object. You just reference the first object with the second one. If eiter of those gets edited both do at the same time since they are the same object after all.
Unfortunately there is no built in way to simply clone an object, but you coud create an overload to create a new object and pass the source object as argument tocopy all the attributes individually. if there are too many attributes you could also use reflection to procedurally copy all attributes defined in the object.

2 Generic list assignment

if class type list is there named
Collection<PurchaseOrderDetail> poDetails = new Collection<PurchaseOrderDetail>();
and another list with same type is there named _poH.PODetail
why _poH.PODetail = poDetails.ToList(); generates an error
Cannot implicitly convert type 'System.Collections.Generic.List'
to 'System.Collections.ObjectModel.Collection'
what is the solution for this, any explanation please.
All the reason behind the question is
_poH.PODetail = poDetails;
made poDetails.RemoveAt(Convert.ToInt32(e.RowIndex)); updates as well so I was searching for some thing like _poH.PODetail = poDetails.ToCollection();
According to the error message, _poH.PODetail is of type Collection, so assigning a list to it doesn’t work. But since poDetails is a collection itself, you can just assign it directly:
poH.PODetail = poDetails;
So you don’t actually need to call ToList() on it to convert it to a list.
There is no ToCollection method you could call on enumerables, but you could use the Collection constructor that takes a list to make it wrap that list and create a readonly collection:
new Collection(poDetails.ToList());
The short answer is simply that the ToList<T> extension returns an instance of List<T> class which, although similar, is not the same type as Collection<T>.
Basically this doesn't work for the same reasons you cannot set a string value to an integer variable.
One thing you can do though, is initializing the content of a new collection instance with an IList<T> instance. Therefore, the following should give you exactly what you want:
_poH.PODetail = new Collection(poDetails.ToList());
Also, as poke suggested, you might also want to assign the PODetail property with the poDetails variable itself.
_poH.PODetail = poDetails;
However, you must remember that Collection<T> is a reference type. This means that the objects in your collection won't be "copied" inside _poH.PODetail; instead, both poDetails and _poH.PODetail will be pointing to the exact same collection. Any changes done to one collection will automatically be reflected on the other.

How to copy one element of a generic collection

I need to copy one element of a generic collection and add it to the list. Something similar to this:
private List<CalculationResult> cantileverResults = new List<CalculationResult>();
cantileverResults.Add(cantileverResults[previousIndex]);
The problem with this solution is that when I modify the new element, the previousIndex element changes as well. I believe this is because they are reference-type, not value-type. How can I just copy (clone?) the information from one element to another without affecting each other any further?
You will need to create a new object when adding it.
This can be done in several ways - a helper method that takes an object of your type (CalculationResult) and returns a completely new one.
Perhaps have a constructor overload that does this.
There are many ways to achieve such a thing - implementing ICloneable and having the Clone method return a new object.
For example, if you were to create a constructor overload, this is how you could use it:
cantileverResults.Add(new CalculationResult(cantileverResults[previousIndex]));

C# object initializers and collections

I'm trying to set up a class so that it's possible to initialize it using an object initializer, but it contains some collections. Ideally I'd like client code to be able to do:
MyClass myObj = new MyClass
{
Name = "Name",
Contents = new[]
{
"Item1",
"Item2"
}
}
However, where Contents needs to be a BindingList<string>. The underlying field stores a readonly reference to this list, and I'd like the setter to essentially do a Clear followed by AddRange to set the contents.
I can't make the Contents property an IEnumerable<string>, because client code wouldn't see the Add method, among many others, at least not without casting it first. I can't make it a BindingList<string> because if I set it, I need to construct a new binding list to pass to it.. this might be possible but I'd rather not introduce the inefficiency of construct a new BindingList<string> solely for the purpose of passing it to the property setter.
The ideal thing to be able to do would be to have the getter return a BindingList<string> and the setter accept IEnumerable<string>, but C# doesn't allow getters/setters on a property to have different types.
Oh, and implicitly casting between BindingList<string> and IEnumerable<string> is a no-no, so I can't do that either (http://blogs.msdn.com/b/peterhal/archive/2005/06/20/430929.aspx).
Is there any way around this?
C# initializer syntax will automatically call the Add method on your property's collection object. That won't call Reset() beforehand of course, but the object is still empty at that point, so it doesn't matter.
Does replacing the list have to use property set syntax? Having a setter replace the content of a collection without actually changing the collection object identity is very unexpected and will likely lead to bugs.
Create a custom collection class that derives from BindingList<string> and add an implicit cast from type string[]
I would recommed encapsulating the BindingList. In this situation go back to the old school way of creating objects so that you aren't creating unnecessary couplings. Favor good OO over language conventions.

C# Returning object from Array leaves pointer to Array item

I have a List<T> and I do the following:
var myObj = List[2]; //Return object at position 2
myObj.Name = "fred"; //If you look at List[2] its name has changed to fred
I tried the following but it still updates the item in the List
var newObj = new MyObj();
var myObj = List[2]; //Return object at position 2
newObj = myObj;
newObj.Name = "fred"; //If you look at List[2] its name has still changed to fred
How can I avoid this pointer remaining so I can update properties without it updating it in the list?
You could make your object implement the ICloneable interface using the MemberwiseClone method and then:
var myObj = List[2];
var newObj = myObj.Clone();
newObj.Name = "fred";
UPDATE:
As pointed out in the comments section it is not recommended to implement the ICloneable interface as it does not specify if it will perform a shallow or deep clone. Just add a Clone method to your class.
This has nothing to do with arrays or lists per se - it's just how reference types work. Here's a simpler demonstration:
MyObj a = new MyObj();
MyObj b = a;
a.Name = "Test";
Console.WriteLine(b.Name); // Will print "Test"
Lists and arrays work the same way - the values stored will be references (assuming they're reference type values) rather than the data for the object itself.
You might want to read my article about reference types and value types for more information.
As others have said, if you really want independent objects you'll need to clone them. I would suggest trying to design around this in another way though, personally.
Jon. In C# the items in your array are stored 'by reference', meaning that you do not hold a copy of the object in the array you hold a reference (a 'pointer') to it. When you retrieve the element you are retrieving the reference, so you now have two references to the same object. As you only have one object when you update the value both references 'see' the new value. To avoid this you need to copy the instance and there are a couple of ways to do this. As Darin mentioned you could have the object implement ICloneable you could also and the object implement a copy constructor, or you could create a new object and populate the new one from the 'old' data. However, be aware that there are issues, the primary one being the problem of 'deep copy'. If your object holds references to other objects, how do you copy those? do you copy the reference or do you chase the references down and 'deep copy' those. There is no single answer to this, just the classic 'it depends!'
What exactly do you want to do anyway? Do you want to update the property of the object in the list, or do you want another object which is a copy of the object in the list but with a different name?
As an alternative to providing a clone method you could provide a copy constructor.
var newObj = new MyObj(List[2]);
newObj.Name = "fred";
you might be able to do this in a single call, depending on what you want to do. If you know you are always going to create a copy with just a different name then you might want to do something like
var newObj = new MyObj(List[2],"fred");
and set the name during the construction.
but without explicitly creating a new object in some way you can't do what you want.
Be aware though that if you object has a property which is anther object, that you might get into the 'deep copy' problem (which is why IClonable is discouraged) as what do you do when you need to copy that object in you newObj? Do you just provide a reference to the same instance? Or do you copy that as well? What if that object has no clone method/copy constructor, what do you do then?
Great comments, thanks but this is what I have implemented:
public MyObj Clone()
{
BinaryFormatter bFormatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
bFormatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
MyObj newObj = (MyObj)bFormatter.Deserialize(stream);
return newObj;
}

Categories

Resources