ノリと勢いでLINQ to Taskをでっち上げてみた。なお、実用性は皆無の模様

#前口上

`Task`で`ContinueWith`使ってたとき、コレ使えば、`Select`、`SelectMany`を構築できるんじゃなかろか？と突発的に思いついたので、勢いで描いてみた。
なお、実用性は皆無だし、とりあえず作れるのか？動くのか？が主目的なので何から何まで残念なことになってますから、その辺はご留意頂きたく。

#拡張メソッドの作成

##Selectを作る。

`Select`メソッドはそんな難しくなかった。

```csharp

public static Task<TResult> Select<TIn, TResult>(this Task<TIn> task, Func<TIn, TResult> selector)
     => task.ContinueWith(x => selector(x.Result));
```

無難に、`ContinueWith`して、`selector`を適用すれば良いだけ。

##SelectManyを作る
こっちはちょっと厄介。

```csharp

		public static Task<TResult> SelectMany<TIn, TResult>(this Task<TIn> task, Func<TIn, Task<TResult>> selector) => task.ContinueWith(x =>
		{
			var t = selector(x.Result);

			if (t.Status == TaskStatus.Created)
			{
				try
				{
					t.Start();
				}
				catch (Exception ex)
				{
					Console.WriteLine(ex.Message);
				}
			}

			t.Wait();
			return t.Result;

		});

		public static Task<TProjected> SelectMany<TIn, TSelected, TProjected>(this Task<TIn> task,
			Func<TIn, Task<TSelected>> selector,
			Func<TIn, TSelected, TProjected> projector) =>
				task.ContinueWith(x =>
				{
					var t = selector(x.Result);

					if (t.Status == TaskStatus.Created)
					{
						try
						{
							t.Start();
						}
						catch (Exception ex)
						{
							Console.WriteLine(ex.Message);
						}
					}

					t.Wait();

					return projector(x.Result, t.Result);
				});
	}
```

両方とも`selector`が`Task`を戻すので、こいつを元の`task`の`ContinueWith`内で待機させる必要がある。
で、待機させるにゃ`Start`してなきゃマズいけど、`TryStart`なんて便利なもんはないので、とりあえず状態見て`Start`叩いてこけたら無視！と言うガバガバな仕様。
さらに言うなら、失敗したとき、無限待機になったときなどは一切合切気にしてないので、その点もご注意頂ければ。。。

#実際使ってみる

実用性は無いにせよ、使えなきゃアレなので、とりあえず使ってみた。

```csharp

internal static void Main()
{
	var a = Task.Run(() => 42);
	var b = Task.Run(() => 84);

	var ret = a.SelectMany(_ => b, (x, y) => x + y).Select(x => x.ToString());
	ret.Wait();
	Console.WriteLine(ret.Result);


	ret = from x in Task.Run(() => 42)
		from y in Task.Run(() => 84)
		select (x + y).ToString();

	ret.Wait();
	Console.WriteLine(ret.Result);
}

```

とりあえず両方とも動いたので、まぁやりたいことは出来たかなって思います。
蛇足ながら、`ContinueWith`のなかでこの場合は、`b`やら、`y`やらが待機する手前、実行時間は
各タスクの実行時間の総和となるので、実際の所実用性は皆無じゃないかと思います。

#最後に

素人考えながら、多分この辺が作れて使えた以上、`Task`はモナドなんじゃなかろか？
と思いました。


#今回使ったソースコード

```csharp

using System;
using System.Threading.Tasks;

namespace TestBench
{
	static class TaskToLinkExtends
	{

		public static Task<TResult> Select<TIn, TResult>(this Task<TIn> task, Func<TIn, TResult> selector)
			=> task.ContinueWith(x => selector(x.Result));

		public static Task<TResult> SelectMany<TIn, TResult>(this Task<TIn> task, Func<TIn, Task<TResult>> selector)
			=> task.ContinueWith(x =>
			{
				var t = selector(x.Result);

				if (t.Status == TaskStatus.Created)
				{
					try
					{
						t.Start();
					}
					catch (Exception ex)
					{
						Console.WriteLine(ex.Message);
					}
				}

				t.Wait();
				return t.Result;

			});

		public static Task<TProjected> SelectMany<TIn, TSelected, TProjected>(this Task<TIn> task,
			Func<TIn, Task<TSelected>> selector,
			Func<TIn, TSelected, TProjected> projector) =>
				task.ContinueWith(x =>
				{
					var t = selector(x.Result);

					if (t.Status == TaskStatus.Created)
					{
						try
						{
							t.Start();
						}
						catch (Exception ex)
						{
							Console.WriteLine(ex.Message);
						}
					}

					t.Wait();

					return projector(x.Result, t.Result);
				});
	}


	internal class Program
	{
		internal static void Main()
		{
			var a = Task.Run(() => 42);
			var b = Task.Run(() => 84);

			var ret = a.SelectMany(_ => b, (x, y) => x + y).Select(x => x.ToString());
			ret.Wait();
			Console.WriteLine(ret.Result);


			ret = from x in Task.Run(() => 42)
				from y in Task.Run(() => 84)
				select (x + y).ToString();

			ret.Wait();
			Console.WriteLine(ret.Result);
		}

	}
}

```