Подтвердить что ты не робот

Анонимный поток С# с синтаксисом Lambda

В общем, я получаю синтаксис С# лямбда. Однако синтаксис анонимного потока не совсем ясен для меня. Может кто-нибудь объяснить, что такое создание потоков, как это происходит на самом деле? Пожалуйста, будьте как можно более подробными, я бы хотел поэтапно поработать над магией, которая делает эту работу.

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

Часть, которую я действительно не понимаю, это Thread(() => ...

Когда я использую этот синтаксис, мне кажется, что я удаляю множество ограничений традиционного ThreadStart, например, для вызова метода, который не имеет параметров.

Спасибо за вашу помощь!

4b9b3361

Ответ 1

() => ... означает, что выражение лямбда не имеет параметров. Ваш пример эквивалентен следующему:

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

// ...

new Thread(worker).Start();

{ ... } в lambda позволяет использовать несколько операторов в лямбда-теле, где обычно вам разрешено только выражение.

Это:

() => 1 + 2

Является эквивалентным:

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

Ответ 2

Как только были какие-то ответы, прежде чем я начал, я просто напишу о том, как дополнительные параметры пробиваются в лямбда.

Короче говоря, это называется закрытием. Давайте рассмотрим ваш пример с помощью new Thread(() => _Transaction_Finalize_Worker(transId, machine, info, newConfigPath)).Start(); на части.

Для замыкания существует разница между полями класса и локальными переменными. Таким образом, предположим, что transId является полем класса (таким образом, доступным через this.transId), а другие являются только локальными переменными.

За кулисами, если лямбда, используемая в компиляторе класса, создает вложенный класс с невыразимым именем, позволяет называть его X для простоты и помещает туда все локальные переменные. Также он пишет лямбда там, поэтому он становится нормальным методом. Затем компилятор перезаписывает ваш метод так, чтобы он создавал X в какой-то момент и заменял доступ к machine, info и newConfigPath с помощью x.machine, x.info и x.newConfigPath соответственно. Также X получает ссылку на this, поэтому лямбда-метод может получить доступ к transId через parentRef.transId.

Ну, это очень упрощено, но близко к реальности.


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
}

Ответ 3

Это анонимный способ создания потока на С#, который только запускает поток (потому что вы используете Start();) Следующие два способа эквивалентны. Если вам нужна переменная Thread, чтобы что-то сделать (например, заблокируйте вызывающий поток, вызвав thread0.join()), тогда вы используете второй.

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

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

Теперь часть метода Thread. Если вы видите объявление Thread, у нас есть следующее (я пропустил еще 3).

public Thread(ThreadStart start);

Thread принимает делегат в качестве параметра. Делегат ссылается на метод. Итак, Thread принимает параметр, который является делегатом. ThreadStart объявляется следующим образом.

public delegate void ThreadStart();

Это означает, что вы можете передать любой метод Thread, который возвращает void и не принимает никаких параметров. Итак, следующие примеры эквивалентны.

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

Теперь мы считаем, что метод ThreadMethod делает мало работы, мы можем сделать его локальным и анонимным. Поэтому нам не нужен метод ThreadMethod.

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

Вы видите, что после того, как делегировать последние фигурные скобки, это эквивалентно нашему ThreadMethod(). Вы также можете сократить предыдущий код, представив инструкцию Lambda (см. MSDN). Это только вы используете и видите, как это закончилось, как показано ниже.

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