Principales respuestas
c# - Al crear nuevo Objeto se actualiza el anterior agregado a List

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
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- Propuesto como respuesta Sergio ParraModerator viernes, 24 de noviembre de 2017 18:27
- Marcado como respuesta Camilo Negrete viernes, 24 de noviembre de 2017 20:36
-
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
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- Propuesto como respuesta Sergio ParraModerator viernes, 24 de noviembre de 2017 18:27
- Marcado como respuesta Camilo Negrete viernes, 24 de noviembre de 2017 20:36
-
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
-
-