Анонимный поток С# с синтаксисом Lambda
В общем, я получаю синтаксис С# лямбда. Однако синтаксис анонимного потока не совсем ясен для меня. Может кто-нибудь объяснить, что такое создание потоков, как это происходит на самом деле? Пожалуйста, будьте как можно более подробными, я бы хотел поэтапно поработать над магией, которая делает эту работу.
(new Thread(() => {
DoLongRunningWork();
MessageBox.Show("Long Running Work Finished!");
})).Start();
Часть, которую я действительно не понимаю, это Thread(() => ...
Когда я использую этот синтаксис, мне кажется, что я удаляю множество ограничений традиционного ThreadStart
, например, для вызова метода, который не имеет параметров.
Спасибо за вашу помощь!
Ответы
Ответ 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();