あなたのDoSomething
例では、MyAwaitableのGetResult
メソッドのタイプはとは関係がないため、コンパイラは文句を言いませんTHuh
。に関連するステートメントTHuh
はですreturn null;
。nullリテラルは暗黙的にに変換可能THuh
であるため、すべて問題ありません。
IEnumerable
に類似したキーワードはawait
ですforeach
。 await
特定のパターンに適合するタイプが必要であり、そうforeach
です。1つは待機可能なタイプを消費するためのメカニズムであり、もう1つは列挙可能なタイプを消費するためのメカニズムです。
一方、イテレータブロック(yield return
および)は、列挙可能な型を定義するyield break
ためのメカニズムです(型を明示的に宣言するのではなく、メソッドを記述します)。ここでの例えはキーワードです。async
async
との間の類似性を詳しく説明するために、戻り値のイテレータブロックには同様にステートメントを含めることができ、戻り値の非同期メソッドにはステートメントを含めることができることyield return
に注意してください。どちらの場合も、戻り式の型がメソッドの戻り型ではなく、メソッドの戻り型の型引数であることに注意してください。IEnumerable<int>
yield return 42;
Task<int>
yield return 42;
まだ読んでいない場合は、これらのトピックに関するEricLippertのブログを読む必要があります。
http://blogs.msdn.com/b/ericlippert/archive/tags/Async/
http://blogs.msdn.com/b/ericlippert/archive/tags/Iterators/
また、Asyncシリーズ以外の継続渡しスタイルに関する投稿は、概念が(私にとっては)初めての場合に役立つ可能性があります。
http://blogs.msdn.com/b/ericlippert/archive/tags/continuation+passing+style/
最後に、例については、MSDNの記事と同じ問題の関連記事にリンクしているEricのブログ投稿と、Bill Wagnerによるフォローアップ記事(http://msdn.microsoft.com/en-us/vstudio/hh533273 )を参照してください。
編集
このルールに従わないように見えるサンプルがいくつかあります。戻り値は到達可能であり、値はデフォルトではありません。この値にアクセスできませんか?もしそうなら、なぜ厄介なアクセスできないreturnステートメントですか?
「本体の端点に到達できない必要がある」というフレーズは、returnステートメントが必要であることを意味します。本文のエンドポイントはreturnステートメントの後にあり、returnステートメントによって到達不能になります。通常のint-returningメソッドを使用した例:
public int Main()
{
Console.WriteLine("X");
//after this comment is the reachable end point of the body; this method therefore won't compile.
}
public int Main()
{
Console.WriteLine("X");
return 0;
//anything after the return statement is unreachable, including the end point of the body; this method therefore will compile.
}
編集2
これは、文字列の後半を計算するウェイターの短くて些細な例です。この例では、結果をコンソールに出力する継続を渡します。スレッドセーフではありません!
public static class StringExtensions
{
public static SubstringAwaiter GetAwaiter(this string s)
{
return new SubstringAwaiter(s, s.Length / 2, s.Length - s.Length / 2);
}
}
public class SubstringAwaiter
{
private readonly string _value;
private readonly int _start;
private readonly int _length;
private string _result;
private Action _continuation;
public SubstringAwaiter(string value, int start, int length)
{
_value = value;
_start = start;
_length = length;
}
public bool IsCompleted { get; private set; }
public void OnCompleted(Action callback)
{
if (callback == null)
return;
_continuation += callback;
}
public string GetResult()
{
if (!IsCompleted)
throw new InvalidOperationException();
return _result;
}
public void Execute()
{
_result = _value.Substring(_start, _length);
IsCompleted = true;
if (_continuation != null)
_continuation();
}
}
public class Program
{
public static void Main()
{
var awaiter = "HelloWorld".GetAwaiter();
awaiter.OnCompleted(() => Console.WriteLine(awaiter.GetResult()));
awaiter.Execute();
}
}