que - tipos de delegados en c#
C#2.0 Threading Question(métodos anónimos) (5)
Aquí hay algunos buenos artículos sobre métodos anónimos en C # y el código que generará el compilador:
http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx
http://blogs.msdn.com/oldnewthing/archive/2006/08/03/687529.aspx
http://blogs.msdn.com/oldnewthing/archive/2006/08/04/688527.aspx
Creo que si lo hiciste:
foreach (FileInfo f in files) { FileInfo f2 = f; //variable declared inside the loop Thread t = new Thread(delegate() { Console.WriteLine(f2.FullName); }); threads.Add(t); }
funcionaría de la forma que quisieras.
Tengo una aplicación simple con el siguiente código:
FileInfo[] files = (new DirectoryInfo(initialDirectory)).GetFiles();
List<Thread> threads = new List<Thread>(files.Length);
foreach (FileInfo f in files)
{
Thread t = new Thread(delegate()
{
Console.WriteLine(f.FullName);
});
threads.Add(t);
}
foreach (Thread t in threads)
t.Start();
Digamos que en el directorio ''I = initialDirectory'' tengo 3 archivos. Esta aplicación debe crear 3 hilos, con cada hilo imprimiendo uno de los nombres de archivo; sin embargo, en su lugar, cada hilo imprimirá el nombre del último archivo en la matriz de ''archivos''.
¿Por qué es esto? ¿Por qué la variable ''f'' del archivo actual no se está configurando correctamente en el método anónimo?
El método anónimo guarda una referencia a la variable en el bloque adjunto, no el valor real de la variable.
Cuando se ejecutan los métodos (cuando se inician los hilos) f
se ha asignado para señalar el último valor de la colección, por lo que los 3 hilos imprimen ese último valor.
Es porque f.FullName
es una referencia a una variable, y no a un valor (que es la forma en que intentó usarlo). En el momento en que realmente inicia los hilos f.FullName se incrementó hasta llegar al final de la matriz.
De todos modos, ¿por qué repetir las cosas aquí dos veces?
foreach (FileInfo f in files)
{
Thread t = new Thread(delegate()
{
Console.WriteLine(f.FullName);
});
threads.Add(t);
t.Start();
}
Sin embargo, esto sigue siendo incorrecto, y quizás incluso peor ya que ahora tiene una condición de carrera para ver qué hilo va más rápido: escribir el elemento de la consola o iterar al siguiente FileInfo.
Es porque el código subyacente para el iterador (foreach) ya se ''itera'' a través de todos los valores en la Lista antes de que comience el hilo ... Entonces cuando comienzan, el valor ''apuntado'' por el iterador es el último en la lista ...
Comience el hilo dentro de la iteración en su lugar ...
foreach (FileInfo f in files)
{
string filName = f.FullName;
Thread t = new Thread(delegate()
{ Console.WriteLine(filName); });
t.Start();
}
No creo que sea posible una carrera aquí ya que no hay memoria compartida accesible desde todos los hilos.
Lo siguiente también funcionaría.
Thread t = new Thread(delegate()
{
string name = f.Name;
Console.WriteLine(name);
});