1

I want to make backup List for Undo/Redo, But the object in the BackUp List will be change after I modified the object in the original List. How can I deal with this problem? "const", "in" seems not working.

private List<GeminiFileStruct> BackUpForUndoRedo(List<GeminiFileStruct> gfl,
            ToolStripMenuItem tm)
        {
            var li =
                (from i in gfl
                select i).ToList();
            tm.Enabled = true;
            return li;
        }

Sorry, it used to be struct. Cause some problem, I change to class. Could struct has Get/Set??? Green hand to C#.

Jared DC
  • 35
  • 6
  • 2
    If the items in the backup list are being modified when changes occur in the original list, that suggests that `GeminiFileStruct` is shockingly badly named and is in fact a reference type (class), not a struct. That in turn means that both lists currently contain references to the same group of objects, not distinct ones. – Damien_The_Unbeliever Jul 15 '21 at 09:03
  • 1
    You don't need `var li = (from i in gfl select i).ToList();` - you can simply write `var li = gfl.ToList();`. Please can you provide the definition of `GeminiFileStruct` as per Damien's comment. – ProgrammingLlama Jul 15 '21 at 09:04
  • @Damien_The_Unbeliever Sorry, it used to be struct. Cause some problem, I change to class. – Jared DC Jul 15 '21 at 09:09
  • @Llama what is desired is a list of clones of original items as I read OP's question (he wants to change the items in the backup list without affecting the items in the original list). This is a case of **deep versus shallow copying**. – Youp Bernoulli Jul 15 '21 at 09:14
  • @BernoulliIT [Here is an example for your own leanring](https://rextester.com/TCXO24568). Notice how a `struct` behaves vs how a reference type behaves? Notice how you get a deep copy out of the box with a struct? – ProgrammingLlama Jul 15 '21 at 09:33
  • Ah! You are right, I read over the struct part – Youp Bernoulli Jul 15 '21 at 13:46

2 Answers2

1

What you need is a so-called deep copy of the list:

Items in the backup list will be clones of the items in the original list. Fresh new instances of items with identical properties.

Not a shallow copy:

A backup list with "just" references to items in the original list. This will cause changes to item A in the backup list to be changed to item A in the original list because they reference the same item .

Have a look at this SO post or any of these web pages: tutorial 1, tutorial 2.

Deep copying is not a trivial programming technique as you will discover. But under the right assumptions in the right context it can be done safely.

Note

As @Llama points out a deep copy of a list with structs is automagically obtained when doing new List<TStruct>(originalListWithStructs). Struct is a value type and behaves different compared to a reference type.

Youp Bernoulli
  • 5,303
  • 5
  • 39
  • 59
1

While Bernoulli IT describes the actual problem with using a shallow copy, I wanted to provide some more background for undo/redo. There are two main approaches for undo/redo

  1. Memento pattern. Before doing a change to an object, a memento is created that can be used to restore the state of said object. This can be applied to the whole application, i.e. before any change, the application state is serialized, just like it would if the user saves to a file. This serialized state can then be restored, just like when loading a file. Assuming there is a function to save to file, and that this represents the application state. Note that serialization/deserialization will implicitly create a deep copy.

  2. Command pattern. Each change should be done by a command that knows how to reverse the change. A downside with this is that it can be complicated to make sure all actions generate these objects correctly.

JonasH
  • 28,608
  • 2
  • 10
  • 23