0

I think this problem is a value/reference instantiate problem in Object Oriented languages like C#. But I'm newbie and I don't know how to turnaround.

I have a method with this piece of code:

    List<CSpropr> listActionpropr = CSpropr.searchList(actionCondition); // Get a list of all records of table PROPR for the 'actioncondition' specified
// For each record...
    foreach (CSpropr instance in listActionpropr)
       {
         instance.ValName = "John";
         instance.ValPhone = 323234232;
         instance.update(); // This make and UPDATE of the record in DB
       }

Later in the same method, I want to use the first version of listActionpropr, before the update. To make a sort of rollback. But when I iterate the listActionpropr variable I get the list of records with the changes in Name and Phone values. For example:

foreach (CSApropr instance1 in listActionpropr )
    {
      instance1.update();
    }

Is there an elegantly way to preserve the value without create a new search to other variable? Like this:

List<CSpropr> listActionpropr = CSpropr.searchList(actionCondition); // Get a list of all records of table PROPR for the 'actioncondition' specified
List<CSpropr> preservedList = CSpropr.searchList(actionCondition); // Get a list of all records of table PROPR for the 'actioncondition' specified
    // For each record...
        foreach (CSpropr instance in listActionpropr)
           {
             instance.ValName = "John";
             instance.ValPhone = 323234232;
             instance.update(); // This make and UPDATE of the record in DB
           }
....

foreach (CSApropr instance1 in preservedList )
        {
          instance1.update();
        }      
milheiros
  • 621
  • 2
  • 14
  • 34
  • Why don't just assign the list to the preserved list ??? – Coder1409 Apr 21 '15 at 09:42
  • 1
    It depends on what the `searchList()` returns. If it always returns new objects, you can do as you wrote. If it always returns the same objects, then no, you can't do it that simply. It is totally implementation specific. – Sami Kuhmonen Apr 21 '15 at 09:45
  • Apropos of your title: an object is an instance of a class. – Rob Apr 21 '15 at 09:47
  • Please see ["Should questions include “tags” in their titles?"](http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles), where the consensus is "no, they should not"! –  Apr 21 '15 at 10:32
  • Well, if you can't use any deep copy method, then your only hope is that the `CSpropr.searchList` returns a list of new CSpropr every time it's called. – Zohar Peled Apr 21 '15 at 11:00

4 Answers4

1

I would use DeepClone in this case with serialization as per this answer : https://stackoverflow.com/a/519512/841467

My fast implementation in LinqPad was :

void Main()
{
    List<CSpropr> listActionpropr = CSpropr.searchList("act"); // Get a list of all records of table PROPR for the 'actioncondition' specified
    List<CSpropr> preservedList = listActionpropr.DeepCopy(); // Get a list of all records of table PROPR for the 'actioncondition' specified
    // For each record...
    foreach (CSpropr instance in listActionpropr)
    {
        instance.ValName = "John";
        instance.ValPhone = 323234232;
        instance.update(); // This make and UPDATE of the record in DB
    }

    foreach (CSpropr instance1 in preservedList )
    {
        instance1.update();
    }
}

// Define other methods and classes here
[Serializable]
public class CSpropr {
    public string ValName {get;set;}
    public int ValPhone {get;set;}

    public void update() {
        ValName.Dump();
        ValPhone.Dump();
    }

    public static List<CSpropr> searchList(string act) {
        return new List<CSpropr> { new CSpropr {ValName = "First", ValPhone = 4444} , new CSpropr {ValName = "First", ValPhone = 4444 }};   
    }
}

public static class GenericCopier
{
    public static T DeepCopy<T>(this T original) where T : class
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(memoryStream, original);
            memoryStream.Seek(0, SeekOrigin.Begin);
            return (T)binaryFormatter.Deserialize(memoryStream);
        }
    }
}

result is :

John 323234232 John 323234232 First 4444 First 4444

Community
  • 1
  • 1
Igoris Azanovas
  • 1,640
  • 1
  • 22
  • 37
  • This might be an overkill for simple objects. if the object is only holding a few simple properties I think it's going to be faster to add a Clone method to it and do something like `OriginalList.ForEach(f => ClonedList.Add(f.Clone()));` Also, [the answers here might help as well](http://stackoverflow.com/questions/222598/how-do-i-clone-a-generic-list-in-c). – Zohar Peled Apr 21 '15 at 10:08
  • Thanks, but i think I can´t make CSpropr Cloneable or Serializable due to other reasons. – milheiros Apr 21 '15 at 10:22
  • Okay if serealizing is not an options i would used @ZoharPeled suggestion, or use AutoMapper. It depends if you program must be extensible and so on... – Igoris Azanovas Apr 21 '15 at 10:28
1

What you are talking about is close to transactions in c# objects. There is no inherent support for object transactions in c#.

Microsoft did start a project on STM (Software Transactional Memory) to support the transaction features for .NET objects. However, the project has already been retired for various reasons.

So, all you can do now is have a separate object for original list. You could either DeepCopy the object with the some helper method as described in other answer or implement IClonable interface for you object, which does the deep copy for you. An example would be :

public class Person : ICloneable
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public Address PersonAddress { get; set; }

    public object Clone()
    {
        Person newPerson = (Person)this.MemberwiseClone();
        newPerson.PersonAddress = (Address)this.PersonAddress.Clone();

        return newPerson;
    }
}

The Address class uses MemberwiseClone to make a copy of itself.

public class Address : ICloneable
{
    public int HouseNumber { get; set; }
    public string StreetName { get; set; }

    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

Cloning a Person:

Person herClone = (Person)emilyBronte.Clone();

The example is taken from one of the excellent blogs in internet for c#

Of course, when I meant object, it's applicable to List<objects> as well.

ANewGuyInTown
  • 5,957
  • 5
  • 33
  • 45
  • Thanks @ANewGuyInTown but I can't change my CSpropr class to be Cloneable. – milheiros Apr 21 '15 at 10:42
  • Well, in that case, if you are not looking at the option of `Deep Cloning` , you could create a wrapper class for your class which implements the IClonable, I will provide you with an example, if you are interested. – ANewGuyInTown Apr 21 '15 at 10:49
  • [See MemberwiseClone documentation](https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx): "The MemberwiseClone method creates a shallow copy by creating a new object, and then copying the nonstatic fields of the current object to the new object. If a field is a value type, a bit-by-bit copy of the field is performed. If a field is a reference type, **the reference is copied but the referred object is not;** therefore, the original object and its clone refer to the same object." – Zohar Peled Apr 21 '15 at 10:57
  • 1
    @ZoharPeled Yes, you are right, hence the separate member-wise clone for object inside `Person` class, which is `Address`. If you look closely, all the fields inside the class are `value types` and any other reference types will have it's own IClonable interface implemented. – ANewGuyInTown Apr 21 '15 at 11:03
  • @ANewGuyInTown I saw you did it correctly. I just thought that it's worth mentioning for clarity. – Zohar Peled Apr 21 '15 at 11:06
  • @ZoharPeled, no worries. – ANewGuyInTown Apr 21 '15 at 11:19
0

Basically you want two identical lists but if you change one element of the list1 it should not affect the same element of list2 . You can do this in various ways: eg using serialization.

Following code will show my way:

Module Module1

Sub Main()

    Dim listone As New List(Of demo) 'first list
    Dim listwo As New List(Of demo)   ' second list
    Dim var1 As Integer
    Dim var2 As String
    Dim obj As New demo()           'first object created in list-1
    obj.id = 1
    obj.name = "sumi"
    listone.Add(obj)                'first object inserted in the list-1
    Dim obj1 As New demo()
    obj1.id = 3
    obj1.name = "more"
    listone.Add(obj1)               'Second object inserted in the list-1
    For Each w In listone
        Dim obj3 As New demo()
        var1 = w.id
        obj3.id = var1
        var2 = w.name
        obj3.name = var2
        listwo.Add(obj3)            'looping all objects of list-1 and adding them in list-2 .Hence making both lists identical

    Next
    For Each p In listone      'making change in the list-1 and this change should not be refelected in list-2
        If (p.id = 1) Then
            p.id = 5
        End If
    Next
    For Each z In listone
        Console.WriteLine(z.id)
        Console.WriteLine(z.name)

    Next
    For Each q In listwo
        Console.WriteLine(q.id)
        Console.WriteLine(q.name)
    Next
    Console.ReadLine()

End Sub
Class demo
    Public name As String
    Public id As Integer
End Class

End Module

Output:
5
sumi
3
more
1
sumi
3
more

Hence cloned list remains unaffected irrespective of changes in original list

-1

You can store your first list object like that:

List<CSpropr> StoreFirstListInTemp(List<CSpropr> listActionpropr)
{
  List<CSpropr> temp = new List<CSpropr>();
  temp.AddRange(listActionpropr);
  return temp;
}
Orkun Bekar
  • 1,447
  • 1
  • 15
  • 36
  • 1
    Downvote reason: Your answer is wrong. your temp List will simply hold another reference for each SCpropr object in the original list. – Zohar Peled Apr 21 '15 at 10:01