带有Lambda语法的C#匿名线程

joc*_*ull 28 c# lambda multithreading

一般来说,我得到了C#的lambda语法.但是匿名线程语法对我来说并不完全清楚.有人可以解释这样的线程创建实际上在做什么吗?请尽可能详细,我希望能够逐步实现让这项工作变得神奇的魔力.

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

我真正不理解的部分是 Thread(() => ...

当我使用这种语法时,似乎我删除了传统的许多限制,ThreadStart例如必须在没有参数的方法上调用.

谢谢你的帮助!

ano*_*ard 36

() => ...只是意味着lambda表达式不带参数.您的示例等效于以下内容:

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

// ...

new Thread(worker).Start();
Run Code Online (Sandbox Code Playgroud)

{ ... }在lambda让你用在lambda体内,在那里通常你只被允许表达多个语句.

这个:

() => 1 + 2
Run Code Online (Sandbox Code Playgroud)

相当于:

() => { return (1 + 2); }
Run Code Online (Sandbox Code Playgroud)

  • 因为lambda表达式可以从其外部范围捕获变量.看看闭包:http://en.wikipedia.org/wiki/Closure_ (computer_science) (3认同)
  • @jocull在我的回答中,我试图描述lambda在C#中是如何工作的. (2认同)

Iva*_*lov 10

由于在我开始之前有一些答案,我将写下额外的参数如何进入lambda.

简而言之,这个东西叫做封闭.让我们分析你的例子new Thread(() => _Transaction_Finalize_Worker(transId, machine, info, newConfigPath)).Start();.

对于闭包,类的字段和局部变量之间存在差异.因此,我们假设这transId是类字段(因此可以访问this.transId),而其他只是局部变量.

在幕后如果在类编译器中使用lambda创建具有不可描述名称的嵌套类,则X为了简单起见,请将其命名,并将所有局部变量放在那里.它也在那里写lambda,所以它成为常规方法.然后编译器重写你的方法,使其产生X在某一时刻,并取代访问machine,infonewConfigPathx.machine,x.infox.newConfigPath分别.还X接收引用this,因此lambda方法可以访问transIdvia 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
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,我想我明白现在发生了什么 - 很多匿名型魔法! (2认同)

Rot*_*eel 6

这是在C#中创建线程的匿名方式,它只是启动线程(因为你使用的是Start();)以下2种方法是等效的.如果你需要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();
Run Code Online (Sandbox Code Playgroud)

现在是Thread方法的一部分.如果你看到Thread声明,我们有以下内容(我省略了3个其他声明).

public Thread(ThreadStart start);
Run Code Online (Sandbox Code Playgroud)

线程将委托作为参数.委托是指方法.所以Thread接受一个委托参数.ThreadStart声明如下.

public delegate void ThreadStart();
Run Code Online (Sandbox Code Playgroud)

这意味着您可以将任何方法传递给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...");
}
Run Code Online (Sandbox Code Playgroud)

现在我们认为ThreadMethod方法做的很少,我们可以将它设置为本地和匿名.所以我们根本不需要ThreadMethod方法.

    new Thread( delegate () 
    {
        Console.WriteLine("Anonymous method Thread job goes here...");
    }).Start();
Run Code Online (Sandbox Code Playgroud)

在委托之后看到最后一个花括号等同于我们的ThreadMethod().您可以通过引入Lambda语句进一步缩短以前的代码(请参阅MSDN).这只是你正在使用,看看它是如何结束如下.

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