MemberwiseClone of aggregates

3

I have in memory (not yet stored in database) an object of type List<NotaFiscal> . I need to pass an item from this list as a parameter to a screen, so that changes are made to that object. However, it may be necessary for the user to cancel the changes, and the object will return to its original state.

Then, when I open the screen that will get this object from NotaFiscal , I make a clone of that object using MemberwiseClone() .

Class Fiscal Note

public class NotaFiscal
{
    public string Numero { get; set; }
    public string Serie { get; set; }
    .........
    public ICollection<NotaFiscalProduto> Produtos { get; set; }

     public NotaFiscal Clone()
     {
        return (NotaFiscal) MemberwiseClone();
     }
}

ClassNoteFiscal class

public partial class TelaNotaFiscal: Window
{
     private readonly NotaFiscal _notaBackup;
     private readonly NotaFiscal _nota;
     private bool _cancelarAlteracao;

     public NotaFiscal Nota => !_cancelarAlteracao ? _nota : _notaBackup;

     public TelaNotaFiscal(NotaFiscal nota)
     {
         InitializeComponent();
         _notaBackup = nota.Clone();
         _nota = nota;
     }
 }

Class

 private void btnNf_Click(object sender, RoutedEventArgs e)
 {
    var botao = (Button)sender;
    var nota = (NotaFiscal)botao.DataContext;
    var telaNota = new TelaNotaFiscal(nota);
    telaNota.Closed += (sen, es) =>
    {
       nota = telaNota.Nota;
     };
     telaNota .ShowDialog();
  }

If the user cancels the change, the Numero and Serie properties return to the previous value. However, if you remove items from _nota.Produtos , this is also reflected in _notaBackup.Produtos

Imediate Window

By analyzing the Imediate I can conclude that the _nota and _notaBackup objects are different, but the zero positions of Produtos are equal objects.

  

_note.Products [0] .GetHashCode ()

     

45644990

     

_notaBackup.Products [0] .GetHashCode ()

     

45644990

     

_nota.GetHashCode ()

     

59505294

     

_notaBackup.GetHashCode ()

     

23797978

What could you do to fix this problem? Or what other alternative to edit this object in memory and reverse the changes if necessary.

    
asked by anonymous 20.02.2017 / 19:28

1 answer

3

You need to make a deep copy. I've already talked about this in another question.

It is not easy to do this in the right way. The simplest and safest is to serialize and deserialize the object. Today almost everyone uses NewtonSoft JSON for this.

Do something like this:

public NotaFiscal Clone() {
    if (Object.ReferenceEquals(source, null)) {
        return default(NotaFiscal);
    }
    var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};
    return JsonConvert.DeserializeObject<NotaFiscal>(JsonConvert.SerializeObject(this), deserializeSettings);

 }

I placed it on GitHub for future reference .

Obviously you can do this as a utility or extension method as well. I did it the way it started.

If something is not serializable you may have problems. The solution probably involves using reflection and copying all fields from the entire object graph. Task is not simple and I will not even get into it.

    
20.02.2017 / 20:05