none
c# - Al crear nuevo Objeto se actualiza el anterior agregado a List RRS feed

  • Pregunta

  • Hola,

    Estoy haciendo un pequeño sistema de inventario que cuenta con una clase "Articulo", y un "List<Articulo>" que va guardando articulos. El problema es que al setear los datos al nuevo objeto modifica el anterior. Por lo cual al querer comparar la ubicación y codigo de barra del que estoy agregando, con el anteriormente agregado, siempre es igual...

    Dejo el Codigo: Clase Articulo.cs

     
    namespace Inventario_Nipon.Negocio
    {
        public class Articulo
        {
            private string codigo;
            private string descripcion;
            private string codigobarra;
            private int cantidad;
            private string ubicacion;
    
            public Articulo(String codigo, String descripcion, String codigobarra, int cantidad, string ubicacion)
            {
                this.codigo = codigo;
                this.descripcion = descripcion;
                this.codigobarra = codigobarra;
                this.cantidad = cantidad;
            }
    
            public Articulo() 
            {
                this.codigo = "";
                this.descripcion = "";
                this.codigobarra = "";
                this.cantidad = 0;
                this.ubicacion = "";
            }
    
            public string ioCodigo
            {
                get { return codigo; }
                set { codigo = value; }
            }
    
            public string ioDescripcion
            {
                get { return descripcion; }
                set { descripcion = value; }
            }
    
            public string ioCodigoBarra
            {
                get { return codigobarra; }
                set { codigobarra = value; }
            }
            public int ioCantidad
            {
                get { return cantidad; }
                set { cantidad = value; }
            }
            public string ioUbicacion
            {
                get { return ubicacion; }
                set { ubicacion = value; }
            }
    //COntinuan los metodos....
          

    Y el evento del Boton Agregar del Programa.cs

    Dejo Comentado Donde Exactamente se produce el problema...

    public partial class CapturaInventario : Form
       { 
            List<Articulo> MaestroArticulos = new List<Articulo>();
            List<Articulo> Inventario = new List<Articulo>();
            Articulo art = new Articulo();
            bool existeMaestro = false;
            //recuperar inventario anterior
    
            public CapturaInventario(List<Articulo> MaestroArticulos)
            {
                InitializeComponent();
                this.MaestroArticulos = MaestroArticulos;
            }
    
    
            private void btnAgregar_Click(object sender, EventArgs e)
            {
                Articulo articulo = new Articulo();
                articulo.ioCodigoBarra = txtCodigoBarra.Text;
    
                for (int i = 0; i < MaestroArticulos.Count; i++)
                {
                    if (MaestroArticulos[i].ioCodigoBarra == articulo.ioCodigoBarra)
                    {
                        lblDescripcion.Text = MaestroArticulos[i].ioDescripcion;
                        articulo = MaestroArticulos[i];
                        existeMaestro = true;
                        i = MaestroArticulos.Count;
                    }
                }
    
    
    //Al completar estas instrucciones el Articulo en List pasa a tener estos datos
    
                articulo.ioCantidad = (int)numCantidad.Value;
                articulo.ioUbicacion = txtUbicacion.Text;
    
    //Fin instrucciones
    
                
                Articulo articuloEncontrado=new Articulo();
    
                int cantInventario = Inventario.Count;
                bool checkExistencia=false;
                bool contado = false;
    
                //Si Articulo no existe en el maestro agregar a Listado de los No existentes
                if (existeMaestro != true)
                {
                    articulo.ioCodigo = art.ioCodigoBarra;
                    articulo.agregarNoExiste(articulo);
                }
    
                //Comprobar doble lectura
                if (cantInventario != 0)
                {
                    for (int i = 0; i < cantInventario; i++)
                    {
                        if (Inventario[i].ioCodigoBarra == articulo.ioCodigoBarra)
                        {
                            articuloEncontrado = Inventario[i];
                            if (Inventario[i].ioCodigoBarra == articulo.ioCodigoBarra && Inventario[i].ioUbicacion == articulo.ioUbicacion)
                            {                            
                                contado = true;
                                i = cantInventario;
                            }
                            else
                            {
                                checkExistencia = true;
                                i = cantInventario;
                            }
                        }
                    }
    
                    if (checkExistencia)
                    {
                        if (MessageBox.Show("THE articulo " + articulo.ioCodigoBarra + "tiene <" + articuloEncontrado.ioCantidad + "> en la ubicación <" + articuloEncontrado.ioUbicacion + "> ¿Desea sumar?", "Confirmar", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                        {
                            art.agregarArticulo(articulo);
                            Inventario.Add(articulo);
                            MessageBox.Show("Registro agregado");
                        }
                        else
                        {
                            txtUbicacion.Text = "";
                            txtCodigoBarra.Text = "";
                            numCantidad.Value = 0;
                        }
                    }
    
                    if (contado)                
                    {
                        if (MessageBox.Show("El articulo " + articulo.ioCodigoBarra + "tiene <" + articuloEncontrado.ioCantidad + "> en la ubicación <" + articuloEncontrado.ioUbicacion + "> ¿Desea sumar?", "Confirmar", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                        {
                            articulo.ioCantidad = articuloEncontrado.ioCantidad + articuloEncontrado.ioCantidad;
                            Inventario = art.modificarArticulo(articulo, Inventario);                        
                            MessageBox.Show("Registro Modificado");
                        }
                        else
                        {
                            txtUbicacion.Text = "";
                            txtCodigoBarra.Text = "";
                            numCantidad.Value = 0;
                        }
                    }
    
                    if(!checkExistencia && !contado)
                    {
                        articulo.agregarArticulo(articulo);
                        Inventario.Add(articulo);
    
                        txtUbicacion.Text = "";
                        txtCodigoBarra.Text = "";
                        numCantidad.Value = 0;
                    }
                }
                else
                {
                    articulo.agregarArticulo(articulo);
                    Inventario.Add(articulo);
    
                    txtUbicacion.Text = "";
                    txtCodigoBarra.Text = "";
                    numCantidad.Value = 0;
                }            
            }
    }
    
    

    Espero puedan ayudarme con esto...

    Saludos,

    Camilo

    viernes, 24 de noviembre de 2017 15:53

Respuestas

  • hola

    Si el codigo pasa por esta linea

    articulo = MaestroArticulos[i];

    estas asignando la misma instancia para todos los agregar, recuerda que los objetos se referencianno se copian

    -----

    ademas si la idea es buscar en una lista, porque no te ayudas con linq

    var result = MaestroArticulos.FirstOrDefault(x=>x.ioCodigoBarra == articulo.ioCodigoBarra);

    pero no asignes el resultado directo ya que es un referencia no una copia


    saludios


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    viernes, 24 de noviembre de 2017 16:12
  • Buenas,

    Como bien te dice Leandro, los objetos de tipo clase se copian por referencia, por lo que modificar 1, modifica todas las copias,

    Lo que podrías hacer, es hacer una "Copia Profunda", esto hace que consigas una copia que NO es por referencia, por lo que puedes modificarla sin afectar al resto, te dejo un link

    Implementing Deep Cloning via Serializing objects

    Basicamente, consiste en crear un metodo de extension que serializa el objeto, y lo deserializa para "Clonarlo", para ello, deberias definir una clase asi:

    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;     
          
    /// <span class="code-SummaryComment"><summary></span>
    /// Provides a method for performing a deep copy of an object.
    /// Binary Serialization is used to perform the copy.
    /// <span class="code-SummaryComment"></summary></span>
    public static class ObjectCopier
    {
     /// <span class="code-SummaryComment"><summary></span>
     /// Perform a deep Copy of the object.
     /// <span class="code-SummaryComment"></summary></span>
     /// <span class="code-SummaryComment"><typeparam name="T">The type of object being copied.</typeparam></span>
     /// <span class="code-SummaryComment"><param name="source">The object instance to copy.</param></span>
     /// <span class="code-SummaryComment"><returns>The copied object.</returns></span>
     public static T Clone<T>(this T source)
     {
      if (!typeof(T).IsSerializable)
      {
        throw new ArgumentException("The type must be serializable.", "source");
      }
      
      // Don't serialize a null object, simply return the default for that object
      if (Object.ReferenceEquals(source, null))
      {
        return default(T);
      }
    
      IFormatter formatter = new BinaryFormatter();
      Stream stream = new MemoryStream();
      using (stream)
      {
        formatter.Serialize(stream, source);
        stream.Seek(0, SeekOrigin.Begin);
        return (T)formatter.Deserialize(stream);
      }
     }
    }

    y en tu codigo cambia

    articulo = MaestroArticulos[i];
    //por
    articulo = MaestroArticulos[i].Clone();

    de tal modo que cuando obtienes el articulo desde MaestroArticulos, vas a obtener un articulo que es una copia por valor

    Si tienes dudas nos comentas

    Atte


    No olvides votar mi comentario si te ha ayudado y marcarlo como respuesta si ha sido la solución, con eso ayudas a mejorar mi reputación en la comunidad y a identificar la respuesta a la gente que tenga el mismo problema.

    Para obtener una respuesta lo más rápida y concisa posible, te recomiendo:

    • Marcado como respuesta Camilo Negrete viernes, 24 de noviembre de 2017 20:37
    viernes, 24 de noviembre de 2017 16:23

Todas las respuestas

  • hola

    Si el codigo pasa por esta linea

    articulo = MaestroArticulos[i];

    estas asignando la misma instancia para todos los agregar, recuerda que los objetos se referencianno se copian

    -----

    ademas si la idea es buscar en una lista, porque no te ayudas con linq

    var result = MaestroArticulos.FirstOrDefault(x=>x.ioCodigoBarra == articulo.ioCodigoBarra);

    pero no asignes el resultado directo ya que es un referencia no una copia


    saludios


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    viernes, 24 de noviembre de 2017 16:12
  • Buenas,

    Como bien te dice Leandro, los objetos de tipo clase se copian por referencia, por lo que modificar 1, modifica todas las copias,

    Lo que podrías hacer, es hacer una "Copia Profunda", esto hace que consigas una copia que NO es por referencia, por lo que puedes modificarla sin afectar al resto, te dejo un link

    Implementing Deep Cloning via Serializing objects

    Basicamente, consiste en crear un metodo de extension que serializa el objeto, y lo deserializa para "Clonarlo", para ello, deberias definir una clase asi:

    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;     
          
    /// <span class="code-SummaryComment"><summary></span>
    /// Provides a method for performing a deep copy of an object.
    /// Binary Serialization is used to perform the copy.
    /// <span class="code-SummaryComment"></summary></span>
    public static class ObjectCopier
    {
     /// <span class="code-SummaryComment"><summary></span>
     /// Perform a deep Copy of the object.
     /// <span class="code-SummaryComment"></summary></span>
     /// <span class="code-SummaryComment"><typeparam name="T">The type of object being copied.</typeparam></span>
     /// <span class="code-SummaryComment"><param name="source">The object instance to copy.</param></span>
     /// <span class="code-SummaryComment"><returns>The copied object.</returns></span>
     public static T Clone<T>(this T source)
     {
      if (!typeof(T).IsSerializable)
      {
        throw new ArgumentException("The type must be serializable.", "source");
      }
      
      // Don't serialize a null object, simply return the default for that object
      if (Object.ReferenceEquals(source, null))
      {
        return default(T);
      }
    
      IFormatter formatter = new BinaryFormatter();
      Stream stream = new MemoryStream();
      using (stream)
      {
        formatter.Serialize(stream, source);
        stream.Seek(0, SeekOrigin.Begin);
        return (T)formatter.Deserialize(stream);
      }
     }
    }

    y en tu codigo cambia

    articulo = MaestroArticulos[i];
    //por
    articulo = MaestroArticulos[i].Clone();

    de tal modo que cuando obtienes el articulo desde MaestroArticulos, vas a obtener un articulo que es una copia por valor

    Si tienes dudas nos comentas

    Atte


    No olvides votar mi comentario si te ha ayudado y marcarlo como respuesta si ha sido la solución, con eso ayudas a mejorar mi reputación en la comunidad y a identificar la respuesta a la gente que tenga el mismo problema.

    Para obtener una respuesta lo más rápida y concisa posible, te recomiendo:

    • Marcado como respuesta Camilo Negrete viernes, 24 de noviembre de 2017 20:37
    viernes, 24 de noviembre de 2017 16:23
  • Muchas gracias Leandro, era eso, ahora me funciona a la perfección. De nuevo, muchas gracias!!!

    viernes, 24 de noviembre de 2017 20:39
  • Muchas gracias Jorge, probaré lo de clonarlo, todos los días se aprende algo nuevo!
    viernes, 24 de noviembre de 2017 20:41