0

したがって、私のコードの一部は、このように非同期的に呼び出されます

Task.Run(() => DoSomethingAsync());

DoSomethingAsync 自体は、次のような DoSomething2Async を呼び出します

private void DoSomething2Async()
{
    Something something = new Something(3);
    Random rand = new Random();
    for (int i = 0; i < 3; i++)
    {
        something.a = rand.Next(1000);

        var task = new Task<int>(()
            => Calculate());

        something.ContinueWith((t)
            => CalculateContinuation(something, task.Result));

        task.Start();
    }

    MessageBox.Show("Do Something2 is done");
}

これは Calculate() メソッドです

private int Calculate()
{
    for (int i = 0; i < 100000000; i++)
    {
        var a = 5; // imitate some job
    }

    return new Random().Next();
}

これは CalculateContinuation() メソッドです

private void CalculateContinuation(Something something, int b)
{
    MessageBox.Show(something.a.ToString(), b.ToString());
}

これがクラスです

class Something : ICloneable
{
    public int a;

    public Something(int aa)
    {
        a = aa;
    }

    public object Clone()
    {
        Something clone = new Something(a);

        return clone;
    }
}

ご覧のCalculateとおり、3 回呼び出され、3 回CalculateContinuationも呼び出されます。CalculateContinuation 2 パラメーターに渡したいのですが、1 つは呼び出し前に構成されたオブジェクト (この場合は何かのインスタンス) で、2 番目はメソッドの結果Calculate。今問題は、の結果はCalculate呼び出しごとに異なり(ランダムであるため)、something.a呼び出しごとに異なる必要があるということです。これもランダムですが、何かがヒットするたびにCalculateContinuation 、何かで構成されたインスタンスを参照しますのループの最終反復DoSomething2Async。(ループの前にヒットした場合、その時点で構成されたオブジェクトを参照すると思います)。私はMessageBoxes結果Calculateが異なる場所を取得することを意味しますが、something.aではありません。私はこれを2日間解決しようとしてきましたが、何をすべきかわかりません。somethingコレクションに sを追加し、各反復で最後を渡そうとしたのクローンを渡そうとしましたがsomething、望ましい結果が得られません。誰かがこのような問題を抱えているかもしれません。この状況での解決策は何ですか。前もって感謝します

編集:

人間が読めるコード

private void RegisterAllUsers()
{
    Person person = new Person(string.Empty);

    for (int i = 0; i < 3; i++)
    {
        person.Name = "Some name"; // different on each iteration

        // create registration task
        var registrationTask = new Task<bool>(()
            => RegisterUser(person));

        // assign continue with, first parameter is person itself and second is the result of RegisterUse
        registrationTask.ContinueWith((task)
            => RegistrationCallback(person, registrationTask.Result));

        registrationTask.Start();
    }
}

private bool RegisterUser(Person person)
{
    // do registration stuff

    return true; // or false if failes 
}

private void RegistrationCallback(Person person, bool succeded)
{
    // when this method executed the reference of person is whatever was set in RegisterAllUsers
    // for the last time, but i want to have reference to the user which was configured on each iteration

    // suppose 1st user is Steve 2nd is Bob and 3rd is Jack
    // when this methid is hit the name of the user is Jack on all 3 callbacks but the succeded parameter
    // is whatever the RegisterUser returned

    // update registered user's status
}

RegisterAllUsers は次のように呼び出します

Task.Run(() => RegisterAllUsers());
4

1 に答える 1

1

コードの編集部分に関して:

Personインスタンスは 1 つだけです: person. 次に、でループを開始しますiperson.Nameループはそれぞれでいっぱいiになり、その間にタスクを開始します。残念ながら、タスクが開始される前に foreach ループが終了し、personインスタンスには最後に割り当てられた値のみが含まれます。したがって、3 つのスケジュールされたタスクがあり、それぞれがperson最後の値のみが割り当てられた 1 つのインスタンスを受け取ります。これは、問題の説明から推測しNameName依存関係があるためです。i

Person問題を解決するには、各タスクのインスタンスを作成し、jループ内で変数を使用します (クロージャーの問題)。

for (int i = 0; i < 3; i++)
{
    int j = i;
    Person person = new Person(string.Empty);
    person.Name = "Some name"; // depends on j this time rather on i
....
于 2013-11-07T08:27:10.303 に答える