2011-07-31 17 views
26

En general obtengo la sintaxis lambda de C#. Sin embargo, la sintaxis del hilo anónimo no es del todo clara para mí. ¿Alguien puede explicar qué hace una creación de subprocesos como esta en realidad? Por favor, sean lo más detallados posible, me encantaría tener una especie de paso a paso sobre la magia que hace que esto funcione.C# Subproceso anónimo con sintaxis Lambda

(new Thread(() => { 
     DoLongRunningWork(); 
     MessageBox.Show("Long Running Work Finished!"); 
    })).Start(); 

La parte que realmente no entiendo es el Thread(() => ...

Cuando utilizo esta sintaxis parece que puedo eliminar una gran cantidad de los límites de una tradicional ThreadStart tales como tener que invocar en un método eso no tiene parámetros

Gracias por su ayuda!

+0

crea un nuevo objeto de hilo que pasa en un método anónimo (un delegado) y lo inicia. Eso es todo. Crear métodos anónimos es esencialmente una forma de pasar un bloque de código como un parámetro de delegado –

Respuesta

34

() => ... solo significa que la expresión lambda no tiene parámetros. Su ejemplo es equivalente a la siguiente:

void worker() 
{ 
    DoLongRunningWork(); 
    MessageBox.Show("Long Running Work Finished!"); 
} 

// ... 

new Thread(worker).Start(); 

El { ... } en el lambda le permiten usar múltiples sentencias en el cuerpo lambda, donde normalmente tan solo te permitirá una expresión.

Este:

() => 1 + 2 

es equivalente a:

() => { return (1 + 2); } 
+0

Esa parte me hace sentido, pero también puedo hacer algo como esto: 'new Thread (() => _Transaction_Finalize_Worker (transId, machine, info, newConfigPath)). Start(); '- ¿por qué ahora puedo pasar todos estos parámetros? – jocull

+3

Porque las expresiones lambda pueden capturar variables de su ámbito externo. Eche un vistazo a los cierres: http://en.wikipedia.org/wiki/Closure_(computer_science) –

+1

closures, yo: http://en.wikipedia.org/wiki/Closure_%28computer_science%29 – anthony

10

Como hubo algunas respuestas antes de empezar a entender, voy a escribir sobre cómo los parámetros adicionales se abren paso en lambda.

En resumen esto llamado cierre. Vamos a analizar su ejemplo con new Thread(() => _Transaction_Finalize_Worker(transId, machine, info, newConfigPath)).Start(); en pedazos.

Para el cierre hay una diferencia entre los campos de la clase y las variables locales. Así, supongamos que transId es un campo de clase (por lo tanto accesible a través de this.transId) y otros son solo variables locales.

Detrás de escena si lambda utilizado en un compilador de clase crea una clase anidada con un nombre indecible, llamémoslo X por simplicidad, y pone todas las variables locales allí. También escribe lambda allí, por lo que se convierte en método normal. A continuación, el compilador reescribe su método para que cree X en algún punto y reemplace el acceso a machine, info y newConfigPath con x.machine, x.info y x.newConfigPath respectivamente. También X recibe referencia a this, por lo que el método lambda podría acceder al transId a través del parentRef.transId.

Bueno, es extremadamente simplificado pero cercano a la realidad.


UPD:

class A 
{ 
    private int b; 

    private int Call(int m, int n) 
    { 
     return m + n; 
    } 

    private void Method() 
    { 
     int a = 5; 
     a += 5; 
     Func<int> lambda =() => Call(a, b); 
     Console.WriteLine(lambda()); 
    } 

    #region compiler rewrites Method to RewrittenMethod and adds nested class X 
    private class X 
    { 
     private readonly A _parentRef; 
     public int a; 

     public X(A parentRef) 
     { 
      _parentRef = parentRef; 
     } 

     public int Lambda() 
     { 
      return _parentRef.Call(a, _parentRef.b); 
     } 
    } 

    private void RewrittenMethod() 
    { 
     X x = new X(this); 
     x.a += 5; 
     Console.WriteLine(x.Lambda()); 
    } 
    #endregion 
} 
+2

Gracias, creo que entiendo lo que está sucediendo ahora: ¡mucha magia de tipo anónimo! – jocull

4

Ésta es la manera anónima para crear un hilo en C#, que acaba de empezar la rosca (porque está utilizando Start();) siguientes 2 formas son equivalentes. Si necesita la variable Thread para hacer algo (por ejemplo, bloquear el hilo de llamada llamando a thread0.join()), entonces usa el segundo.

new Thread(() => 
{ 
    Console.WriteLine("Anonymous Thread job goes here..."); 
}).Start(); 

var thread0= new Thread(() => 
{ 
    Console.WriteLine("Named Thread job goes here..."); 
}); 
thread0.Start(); 

Ahora la parte del método Thread. Si ves la declaración del hilo, tenemos lo siguiente (omití otros 3).

public Thread(ThreadStart start); 

El hilo toma un delegado como parámetro. Delegado es referencia a un método. Entonces Thread toma un parámetro que es un delegado. ThreadStart se declara así.

public delegate void ThreadStart(); 

Significa que puede pasar cualquier método al hilo que devuelva el vacío y no toma ningún parámetro. Entonces los siguientes ejemplos son equivalentes.

ThreadStart del = new ThreadStart(ThreadMethod); 
var thread3 = new Thread(del); 
thread3.Start(); 

ThreadStart del2 = ThreadMethod; 
var thread4 = new Thread(del2); 
thread4.Start(); 

var thread5 = new Thread(ThreadMethod); 
thread5.Start(); 

//This must be separate method 
public static void ThreadMethod() 
{ 
    Console.WriteLine("ThreadMethod doing important job..."); 
} 

Ahora que creemos que el método ThreadMethod está haciendo poco trabajo podemos hacerlo a nivel local y anónimo. Por lo tanto, no necesitamos el método ThreadMethod en absoluto.

new Thread(delegate() 
    { 
     Console.WriteLine("Anonymous method Thread job goes here..."); 
    }).Start(); 

Ves después delegado a durar entre llaves es equivalente a nuestro ThreadMethod(). Puede acortar aún más el código anterior introduciendo la declaración de Lambda (consulte MSDN). Esto es solo lo que está usando y vea cómo se ha terminado de la siguiente manera.

new Thread(() => 
{ 
    Console.WriteLine("Lambda statements for thread goes here..."); 
}).Start();