-2

I am having really a weird issue with my current project. I have sample classes that will hold some data as a collection (List<SampleData>). and I have used another stack collection (Stack<SampleData>) for logging the data that was added to the first list. after modifying the first list's first index data, the stack data was modified without my knowledge.

public class ActionLog
    {
        private Stack<SampleData> UndoStack;
        public ActionLog()
        {
            UndoStack = new();
        }
        public void Log(SampleData Data)
        {
            UndoStack.Push(Data);
            foreach (var item in UndoStack)
                System.Console.WriteLine($"{item.Name}");
        }
    }
public class ActivityControl
    {
        public ActionLog Logger { get; set; } = new ActionLog();
        public List<SampleData> Datas { get; set; } = new List<SampleData>();
        public void Initiallize(List<SampleData> datas)
        {
            Datas.AddRange(datas);
            Logger.Log(datas[0]);
        }
    }
 internal class Program
    {
        static ActivityControl contorl = new ActivityControl();
        static void Main(string[] args)
        {
            List<SampleData> list = new List<SampleData>();
            SampleData data = new SampleData()
            {
                Name = "Data 1"
            };
            SampleData data2 = new SampleData()
            {
                Name = "Data 2"
            };
            list.Add(data);
            list.Add(data2);
            contorl.Initiallize(list);
            contorl.Datas[0].Name = "Data 11";
            contorl.Logger.Log(new SampleData() { Name = "Fake Data" });
            Console.ReadKey();
        }
    }

The out put for the above code should be : Data 1 , Fake Data, Data 1 but i am seeing Data 1, Fake Data, Data 11

  • 1
    Please can you provide a [mcve]. This seems unnecessarily complicated. – ProgrammingLlama Jan 18 '22 at 05:55
  • this is the simplest code that i can provide, sorry for the mess! can you please help? i have spent 5 days on this issue. – Kidus Daniel Jan 18 '22 at 05:59
  • Can you explain why you expect `Data 1` instead of `Data 11`? Although you haven't provided the type definition, it seems very likely that `SampleData` is a reference type (a class). If that's the case, then this is entirely expected behaviour regardless of the collection type. – ProgrammingLlama Jan 18 '22 at 06:00
  • 1
    Take a look here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters - pay close attention to the examples and their outputs. – ProgrammingLlama Jan 18 '22 at 06:01
  • I just wanted to log the data that was added on the first List. so that i can go back to the first result whenever it is needed. here is a git link so that you can test this issue. https://github.com/lazyCoder-max/ConsoleApp1.git – Kidus Daniel Jan 18 '22 at 06:04
  • 1
    It sounds like you need to add a _copy_ of `SampleData` to your `Stack`. – ProgrammingLlama Jan 18 '22 at 06:05
  • yes, that is exactly what I wanted to do. but now, it is assigning replacing all the stack values with a newer data. – Kidus Daniel Jan 18 '22 at 06:10
  • I strongly suggest you read the documentation link I sent you. When you pass a reference type (an instance of a class) to a method, you pass a COPY of its REFERENCE. So you end up with two references to the SAME OBJECT in memory. If you want to COPY a reference type, you need to construct a new reference type containing the same data. – ProgrammingLlama Jan 18 '22 at 06:16
  • Your question is a duplicate of this one: https://stackoverflow.com/questions/2156482/why-does-adding-a-new-value-to-list-overwrite-previous-values-in-the-list and relates to this one: https://stackoverflow.com/questions/5843958/how-to-make-a-copy-of-a-reference-type – ProgrammingLlama Jan 18 '22 at 06:16

1 Answers1

0

The issue that i was having was related to Deep Copy and Shallow Copy. I added a List<SampleData>DeepCopy() method in SampleData class then call the method when it is first assigned. The following code resolves the issue:

public class SampleData
    {
        public string Name { get; set; }
        public SampleData DeepCopy()
        {
            var copy = new SampleData();
            copy.Name = this.Name;
            return copy;
        }
    }
public class ActionLog
    {
        private Stack<List<SampleData>> UndoStack;
        public ActionLog()
        {
            UndoStack = new();
        }
        public void Log(List<SampleData> Data)
        {

            UndoStack.Push(Data);
            foreach (var item in UndoStack)
                System.Console.WriteLine($"{item[0].Name}");
        }
    }
public class ActivityControl
    {
        public ActionLog Logger { get; set; } = new ActionLog();
        public List<SampleData> Datas { get; set; }

        public void Initiallize(List<SampleData> datas)
        {
            Datas = datas;
            List<SampleData> datas1 = new List<SampleData>();
            foreach (var dt in Datas)
            {
                datas1.Add(dt.DeepCopy());
            }

            Logger.Log(datas1);
        }
    }
internal class Program
    {
        static ActivityControl contorl = new ActivityControl();
        static void Main(string[] args)
        {
            List<SampleData> list = new List<SampleData>();
            SampleData data = new SampleData()
            {
                Name = "Data 1"
            };
            SampleData data2 = new SampleData()
            {
                Name = "Data 2"
            };
            list.Add(data);
            list.Add(data2);
            contorl.Initiallize(list);
            contorl.Datas[0].Name = "Data 11";
            contorl.Logger.Log(contorl.Datas);
            Console.ReadKey();
        }
    }