C # Thread anonyme avec la syntaxe Lambda

En général, je reçois la syntaxe lambda de C#. Cependant, la syntaxe du thread anonyme n'est pas complètement claire pour moi. Quelqu'un peut-il expliquer ce qu'une création de thread comme celle-ci fait réellement? Veuillez être aussi précis que possible, j'aimerais avoir une sorte d'étape-par-étape sur la magie qui fait ce travail.

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

La partie que je ne comprends vraiment pas est le Thread(() => ...

Lorsque j'utilise cette syntaxe, il semble que je supprime beaucoup des limites d'un ThreadStart traditionnel comme avoir à invoquer sur un méthode qui n'a pas de paramètres.

Merci pour votre aide!

27
demandé sur hoang 2011-07-31 07:04:29

3 réponses

() => ... cela signifie simplement que l'expression lambda ne prend aucun paramètre. Votre exemple est équivalent à ce qui suit:

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

// ...

new Thread(worker).Start();

Le { ... } dans le lambda vous permet d'utiliser plusieurs instructions dans le corps lambda, où normalement vous ne seriez autorisé qu'une expression.

Ceci:

() => 1 + 2

Est équivalent à:

() => { return (1 + 2); }
35
répondu anonymous coward 2011-07-31 03:09:02

Comme il y avait quelques réponses avant de commencer, je vais simplement écrire sur la façon dont des paramètres supplémentaires font leur chemin dans lambda.

En bref cette chose appelée fermeture . Permet de disséquer votre exemple avec new Thread(() => _Transaction_Finalize_Worker(transId, machine, info, newConfigPath)).Start(); en morceaux.

Pour la fermeture, il y a une différence entre les champs de classe et les variables locales. Supposons donc que transId est un champ de classe (donc accessible via this.transId) et que d'autres ne sont que des variables locales.

Dans les coulisses si lambda utilisé dans un le compilateur de classes crée une classe imbriquée avec un nom indicible, permet de la nommer X pour plus de simplicité et d'y placer toutes les variables locales. En outre, il écrit lambda là-bas, donc il devient méthode normale. Ensuite, le compilateur réécrit votre méthode afin qu'elle crée X à un moment donné et remplace l'accès à machine, info et newConfigPath avec x.machine, x.info et x.newConfigPath respectivement. X reçoit également une référence à this, donc lambda-method pourrait accéder à transId via parentRef.transId.

Eh bien, c'est extrêmement simplifié mais proche de réalité.


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
}
10
répondu Ivan Danilov 2011-07-31 03:29:53

C'est une façon anonyme de créer un thread en C # qui commence juste le thread (parce que vous utilisez Start();) Suivant 2 façons sont équivalentes. Si vous avez besoin d'une variable Thread pour faire quelque chose (par exemple, bloquez le thread appelant en appelant thread0.join ()), alors vous utilisez le 2ème.

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

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

Maintenant, la partie méthode Thread. Si vous voyez la déclaration de Thread, nous avons ce qui suit (j'ai omis 3 autres).

public Thread(ThreadStart start);

Thread prend un délégué comme paramètre. Le délégué fait référence à un méthode. Fil prend un paramètre qui est un délégué. ThreadStart est déclaré comme ceci.

public delegate void ThreadStart();

Cela signifie que vous pouvez passer n'importe quelle méthode à Thread qui renvoie void et ne prend aucun paramètre. Donc les exemples suivants sont équivalents.

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...");
}

Maintenant, nous pensons que la méthode ThreadMethod fait peu de travail, nous pouvons le rendre local et anonyme. Nous n'avons donc pas besoin de la méthode ThreadMethod.

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

Vous voyez après le délégué à la dernière accolades est équivalent à notre ThreadMethod (). Vous pouvez raccourcir davantage le code précédent en introduisant L'instruction Lambda (voir MSDN). C'est juste que vous utilisez et voyez comment il a été fini comme suit.

new Thread( () =>
{
    Console.WriteLine("Lambda statements for thread goes here...");
}).Start();
5
répondu RotatingWheel 2015-10-29 11:22:27