web-dev-qa-db-ja.com

Lambda構文を使用したC#匿名スレッド

一般的に、C#のラムダ構文を取得します。しかし、匿名スレッドの構文は私には完全に明確ではありません。このようなスレッド作成が実際に行っていることを誰かが説明できますか?できるだけ詳しく説明してください。この作品を作成する魔法について、少しずつ説明していきたいと思います。

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

私が本当に理解していない部分はThread(() => ...です

この構文を使用すると、パラメーターを持たないメソッドで呼び出す必要があるなど、従来のThreadStartの多くの制限を削除したようです。

ご協力いただきありがとうございます!

28
jocull

() => ...は、ラムダ式がパラメーターを取らないことを意味します。あなたの例は以下と同等です:

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

// ...

new Thread(worker).Start();

{ ... }ラムダでは、ラムダ本体で複数のステートメントを使用できます。通常は、式のみが許可されます。

この:

() => 1 + 2

以下と同等です:

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

始める前にいくつかの答えがあったので、追加のパラメーターがどのようにラムダに移行するかについて説明します。

要するに、このことはclosureと呼ばれます。 new Thread(() => _Transaction_Finalize_Worker(transId, machine, info, newConfigPath)).Start();を使用した例を細かく分析します。

クロージャの場合、クラスのフィールドとローカル変数には違いがあります。したがって、transIdがクラスフィールド(this.transIdからアクセス可能)であり、その他が単なるローカル変数であると仮定しましょう。

クラスコンパイラで使用されるlambdaが、口に出せない名前でネストされたクラスを作成し、簡単にするためにXという名前を付け、すべてのローカル変数をそこに置く場合、舞台裏で。また、そこにラムダを書き込むため、通常のメソッドになります。次に、コンパイラは、ある時点でXを作成し、machineinfo、およびnewConfigPathへのアクセスをそれぞれx.machinex.info、およびx.newConfigPathに置き換えるようにメソッドを書き換えます。また、Xthisへの参照を受け取るため、ラムダメソッドはparentRef.transIdを介して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
}
10
Ivan Danilov

これは、スレッドを開始するだけのC#でスレッドを作成する匿名の方法です(Start()を使用しているためです)。次の2つの方法は同等です。スレッド変数を使用して何かを行う必要がある場合(たとえば、thread0.join()を呼び出して呼び出しスレッドをブロックする場合)、2番目のスレッドを使用します。

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

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

次に、Threadメソッド部分。スレッド宣言が表示された場合、次のようになります(他の3つは省略しました)。

public Thread(ThreadStart start);

スレッドはパラメータとしてデリゲートを取ります。デリゲートはメソッドへの参照です。そのため、スレッドはデリゲートであるパラメーターを受け取ります。 ThreadStartは次のように宣言されます。

public delegate void ThreadStart();

つまり、voidを返し、パラメーターを受け取らないメソッドをThreadに渡すことができます。したがって、次の例は同等です。

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();
6
RotatingWheel