El codigo para este articulo aplica a C# 2.0
Una tarea mas o menos comun cuando usamos una lista generica, es borrar elementos de esta, vamos a ver que alternativas tenemos:
#1 La forma definitivamente equivocada de hacerlo:
List<Person> l1 = GetList();
//*** The wrong way
foreach (Person p in l1) {
if (p.Age > 30)
l1.Remove(p);
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Este codigo nos dara una excepcion InvalidOperationException: "Collection was modified; enumeration operation may not execute."
#2 Funciona mas o menos (y nos permite ejecutar una accion en cada elemento que vamos a borrar)
List<int> ints = new List<int>();
ints.Add(1);
ints.Add(2);
ints.Add(3);
ints.Add(4);
ints.Add(5);
ints.Add(6);
ints.ForEach(delegate(int i) {
if ((i % 2) == 0) {
Console.WriteLine("removing"+i.ToString());
ints.Remove(i);
}
});
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Si corres este codigo funcionara perfectamente, pero la verdad es que tiene un problema grande, si agregaras los numeros pares primero, verias que no los borra todos, y no te da una excepcion ni nada, simplemente se sale del foreach y continua; asi que este metodo funciona, pero solo en condiciones especiales, lo cual lo hace codigo peligroso
#3 La forma correcta: recorremos la coleccion hacia atras y borramos elementos cuando necesitamosint x = ints2.Count;
while (--x>=0) {
if (ints2[x] < 4)
ints2.RemoveAt(x);
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
#4 Una mejor manera: La lista generica trae un metodo ya incluido que nos sirve para borrar multiples elementos
ints2.RemoveAll(delegate(int i) {
return i <4;
});.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
#5 Pero que pasa si quiero ejecutar una accion en cada elemento que se borre?
ints2.RemoveAll(delegate(int i) {
if (i < 4) {
//*** Perform action here
Console.WriteLine("removing :" + i.ToString());
return true;
}
else
return false;
});
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Si el elemento fuera una clase, podrias mandar llamar uno de sus metodos antes de borrarlo (por ejemplo una llamada a la base de datos)
Mas adelante escribire en detalle porque exactamente las alternativas #1 y #2 no funcionan
salu2