C# > Taskに引数を渡し復帰値を取得する

#背景
Task<TResult>クラスには前から興味があったのですが、引数をどう渡せば良いのか分からなかったので、いろいろ調べて自分なりにサンプルを作成してみました。
参考になれば幸いです。
#サンプルについて
時間のかかる処理として素数の集合を求めるメソッドを用意し、それを同期で呼び出す方法と非同期(Task)で呼び出す方法を試してみました。そのメソッドには素数を求める為の最大の数、例えば100を指定したら0～100までの間にある素数の配列を返すようになっています。
#苦労した点
頭が悪いので、
`return new Task<List<int>>(o => GetPrimes((int)o), n);`
の一文を導き出すのに1週間掛かりました(笑)。
#第2版
[laughter](http://qiita.com/laughter)さん、[chocolamint](http://qiita.com/chocolamint)さん、[ozwk](http://qiita.com/ozwk)さんから改善点や解説を頂きました。
本当に勉強になりました。本当にありがとうございました。
教えて頂いた事を踏まえて、備忘録としてサンプルを修正しました。
#サンプル (第2版)
**GitHub** [TestPrime](https://github.com/shimodateakira/TestPrime.git)

```Program.cs:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;

namespace TestPrime
{
    class Program
    {
        static void Main(string[] args)
        {
            const int PrimesCount = 1000000;
            List<int> primes;
            Prime prime = new Prime();
            Stopwatch sw = new Stopwatch();

            // 同期で呼び出す
            sw.Reset();
            sw.Start();
            primes = prime.GetPrimes(PrimesCount);
            sw.Stop();
            Console.WriteLine("同期で呼び出す");
            Console.WriteLine($"{nameof(sw.Elapsed)} = {sw.Elapsed}");
            Console.WriteLine($"{nameof(primes.Count)} = {primes.Count}");
#if DEBUG
            Debug.WriteLine(string.Join(" ", primes.GetRange(0, 20)));
#endif

            // 同期で呼び出す
            sw.Reset();
            sw.Start();

            // 非同期はこの呼び方でもよいが．．．．
            //Task<List<int>> task = prime.GetPrimesAsync(PrimesCount);
            //task.Start();

            // 利用する側(Programクラス)が非同期で呼び出す方が望ましい
            Task<List<int>> task = Task.Run(() => prime.GetPrimes(PrimesCount));

            sw.Stop();

            // タスクが終了するまで待つ。が．．．
            // task.ResultがWaitを兼ねている。
            // つまり、Resultを取得できるようになるまで待機する。
            //task.Wait();

            primes = task.Result;
            Console.WriteLine("\n非同期で呼び出す");
            Console.WriteLine($"{nameof(sw.Elapsed)} = {sw.Elapsed}");
            Console.WriteLine($"{nameof(primes.Count)} = {primes.Count}");

            Console.WriteLine("\n\nPush any key!");
            Console.ReadKey();
        }
    }
}
```
```Prime.cs:
using System.Collections.Generic;
using System.Threading.Tasks;

namespace TestPrime
{
    /// <summary>
    /// 素数を求めるクラス
    /// </summary>
    public class Prime
    {
        List<int> primes = new List<int>() { 2 };

        /// <summary>
        /// 引数 n までの素数を求める(同期型)
        /// </summary>
        /// <param name="n">求める素数の最大数</param>
        /// <returns>GetPrimesを実行するTask</returns>
        public Task<List<int>> GetPrimesAsync(int n)
        {
            // 引数を渡して復帰値を得るTaskを生成
            //return new Task<List<int>>(o => GetPrimes((int)o), n);

            // 上記よりシンプルな記述
            // 引数はnをキャプチャし使用している
            return new Task<List<int>>(() => GetPrimes(n));
        }

        /// <summary>
        /// 引数 n までの素数を求める(非同期型)
        /// </summary>
        /// <param name="n">求める素数の最大数</param>
        /// <returns>素数の配列</returns>
        public List<int> GetPrimes(int n)
        {
            for (int i = 2; i <= n; i++)
            {
                int primesCount = primes.Count;
                bool notPrimeFlag = false;
                for (int j = 0; j < primesCount; j++)
                {
                    if ((i % primes[j]) == 0)
                    {
                        notPrimeFlag = true;
                        j = primesCount;
                        break;
                    }
                }
                if (!notPrimeFlag)
                {
                    primes.Add(i);
                }
            }
            return primes;
        }
    }
}
```
#実行結果
**コンソール**
同期で呼び出す
Elapsed = 00:00:22.1918873
Count = 78498

非同期で呼び出す
Elapsed = 00:00:00.0004974
Count = 78498


Push any key!

**[出力]ウィンドウ**
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71