私はいくつかの非同期機能を持つインターフェイスを持っています。インタフェースを実装するクラスの中には待つものがないものもありますし、単にスローするものもあります。それはすべての警告と少し面倒です。
使用しない場合は非同期関数で待ちます。
メッセージを抑制することは可能ですか?
public async Task<object> test()
{
throw new NotImplementedException();
}
警告CS1998:この非同期メソッドには 'await'演算子がないため実行されます 同期的に待つために 'await'演算子を使うことを検討してください ノンブロッキングAPI呼び出し、またはCPUに制約のある作業を行うための 'Task.Run(...)'の待機 バックグラウンドスレッドで。
私はいくつかの非同期機能を持つインターフェイスを持っています。
返すメソッドTask
、 私は信じている。async
は実装の詳細なので、インターフェースメソッドには適用できません。
インタフェースを実装するクラスの中には待つものがないものもありますし、単にスローするものもあります。
このような場合は、以下の事実を利用できます。async
実装の詳細です。
何もない場合await
それからあなたは戻ることができますTask.FromResult
:
public Task<int> Success() // note: no "async"
{
... // non-awaiting code
int result = ...;
return Task.FromResult(result);
}
投げる場合NotImplementedException
手順はもう少し手間がかかります。
public Task<int> Fail() // note: no "async"
{
var tcs = new TaskCompletionSource<int>();
tcs.SetException(new NotImplementedException());
return tcs.Task;
}
あなたが投げるメソッドがたくさんあるならNotImplementedException
(それ自体は、デザインレベルのリファクタリングが有効であることを示している可能性があります)、それからあなたは言葉遣いを補助クラスにまとめることができます:
public static class TaskConstants<TResult>
{
static TaskConstants()
{
var tcs = new TaskCompletionSource<TResult>();
tcs.SetException(new NotImplementedException());
NotImplemented = tcs.Task;
}
public static Task<TResult> NotImplemented { get; private set; }
}
public Task<int> Fail() // note: no "async"
{
return TaskConstants<int>.NotImplemented;
}
同じ戻り型を持つ各メソッドがそれぞれのメソッドを共有できるため、ヘルパークラスはGCが収集しなければならないゴミも削減します。Task
そしてNotImplementedException
オブジェクト
他にもいくつかありますAsyncExライブラリの「タスク定数」型の例。
Task<T>
から継承Task
、同じ解決策(Task.FromResult
、TaskCompletionSource
)うまく働きます。単なるプレーンを作成するための簡単で効率的な方法はありません。Task
そのようなので、それを作成するのが最善ですTask<T>
そして(暗黙のうちに)それをにキャストするTask
。 - Stephen ClearyTask
。その代わりに、あなたのメソッドはそれを作成する機会さえも得る前に投げます。Task
。最良のパターンは、async
なしの方法await
演算子。これにより、メソッド内のコードはすべての一部として処理されます。Task
。 - Bob Meyersawait Task.FromResult(0);
あなたの方法に。これは(Task.Yield()とは異なり)パフォーマンスに大きな影響を与えません。 - Bob Meyers
関数の本体を単純にし、それをサポートするコードを記述したくない場合は、#pragmaを使用して警告を抑制することもできます。
#pragma warning disable 1998
public async Task<object> Test()
{
throw new NotImplementedException();
}
#pragma warning restore 1998
これで十分に一般的な場合は、ファイルの先頭にdisableステートメントを配置して復元を省略することができます。
http://msdn.microsoft.com/en-us/library/441722ys(v=vs.110).aspx
asyncキーワードを保持するもう1つの方法は(それを保持したい場合)、次のように使用することです。
public async Task StartAsync()
{
await Task.Yield();
}
メソッドを作成したら、文を削除するだけです。 メソッドが何かを待つかもしれないが、すべての実装が実際にはそうではないとき、私は特にこれをたくさん使います。
Task.Run
コール。 - Andrew ThekenTask.CompletedTask
もう存在しないようです。 - Sebastián VansteenkisteTask.FromResult
より良い答えです。それならば、あります例外をスローしようとしている、それは別の答えが出てきたようですTask.FromException
これを決して理想的な解決策にしないでください。あなたは同意しますか? - BlueMonkMN
私はこれが古いスレッドであることを知っています、そしておそらくこれはすべての用途に正しい効果をもたらすわけではありませんが、次のコードはまだメソッドを実装していないときにNotImplementedExceptionをスローできるようになります。メソッドシグネチャを変更することなくそれが問題であるならば、私はそれについて知ることがうれしいですが、それは私にとってほとんど重要ではありません:私はとにかく開発中にこれを使うので、それがどのように行われるかはそれほど重要ではありません。それでも、なぜそれが悪い考えであるかについて、私はうれしく思います。
public async Task<object> test()
{
throw await new AwaitableNotImplementedException<object>();
}
これを可能にするために私が追加したタイプがあります。
public class AwaitableNotImplementedException<TResult> : NotImplementedException
{
public AwaitableNotImplementedException() { }
public AwaitableNotImplementedException(string message) : base(message) { }
// This method makes the constructor awaitable.
public TaskAwaiter<AwaitableNotImplementedException<TResult>> GetAwaiter()
{
throw this;
}
}
Stephen's Answerの更新と同じように、もう書く必要はありません。TaskConstants
新しいヘルパーメソッドがあるのでクラス:
return Task.FromException(new NotImplementedException());
あなたが答えで見つけることができるさまざまな解決策の違いがあり、厳密に言えば、呼び出し側がどのようにasyncメソッドを呼び出そうとしているか知っておくべきですが、メソッドの結果に ".Wait()"を仮定するTask.CompletedTaskを返します。「最高の解決策です。
BenchmarkDotNet=v0.10.11, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.192)
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233537 Hz, Resolution=309.2589 ns, Timer=TSC
.NET Core SDK=2.1.2
[Host] : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
Clr : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2600.0
Core : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
Method | Job | Runtime | Mean | Error | StdDev | Median | Min | Max | Rank | Gen 0 | Gen 1 | Gen 2 | Allocated |
--------------- |----- |-------- |-------------:|------------:|------------:|-------------:|-------------:|-------------:|-----:|-------:|-------:|-------:|----------:|
CompletedAwait | Clr | Clr | 95.253 ns | 0.7491 ns | 0.6641 ns | 95.100 ns | 94.461 ns | 96.557 ns | 7 | 0.0075 | - | - | 24 B |
Completed | Clr | Clr | 12.036 ns | 0.0659 ns | 0.0617 ns | 12.026 ns | 11.931 ns | 12.154 ns | 2 | 0.0076 | - | - | 24 B |
Pragma | Clr | Clr | 87.868 ns | 0.3923 ns | 0.3670 ns | 87.789 ns | 87.336 ns | 88.683 ns | 6 | 0.0075 | - | - | 24 B |
FromResult | Clr | Clr | 107.009 ns | 0.6671 ns | 0.6240 ns | 107.009 ns | 106.204 ns | 108.247 ns | 8 | 0.0584 | - | - | 184 B |
Yield | Clr | Clr | 1,766.843 ns | 26.5216 ns | 24.8083 ns | 1,770.383 ns | 1,705.386 ns | 1,800.653 ns | 9 | 0.0877 | 0.0038 | 0.0019 | 320 B |
CompletedAwait | Core | Core | 37.201 ns | 0.1961 ns | 0.1739 ns | 37.227 ns | 36.970 ns | 37.559 ns | 4 | 0.0076 | - | - | 24 B |
Completed | Core | Core | 9.017 ns | 0.0690 ns | 0.0577 ns | 9.010 ns | 8.925 ns | 9.128 ns | 1 | 0.0076 | - | - | 24 B |
Pragma | Core | Core | 34.118 ns | 0.4576 ns | 0.4281 ns | 34.259 ns | 33.437 ns | 34.792 ns | 3 | 0.0076 | - | - | 24 B |
FromResult | Core | Core | 46.953 ns | 1.2728 ns | 1.1905 ns | 46.467 ns | 45.674 ns | 49.868 ns | 5 | 0.0533 | - | - | 168 B |
Yield | Core | Core | 2,480.980 ns | 199.4416 ns | 575.4347 ns | 2,291.978 ns | 1,810.644 ns | 4,085.196 ns | 10 | 0.0916 | - | - | 296 B |
注意:FromResult
直接比較することはできません。
テストコード
[RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn]
[ClrJob, CoreJob]
[HtmlExporter, MarkdownExporter]
[MemoryDiagnoser]
public class BenchmarkAsyncNotAwaitInterface
{
string context = "text context";
[Benchmark]
public int CompletedAwait()
{
var t = new CompletedAwaitTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}
[Benchmark]
public int Completed()
{
var t = new CompletedTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}
[Benchmark]
public int Pragma()
{
var t = new PragmaTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}
[Benchmark]
public int Yield()
{
var t = new YieldTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}
[Benchmark]
public int FromResult()
{
var t = new FromResultTest();
var t2 = t.DoAsync(context);
return t2.Result;
}
public interface ITestInterface
{
int Length { get; }
Task DoAsync(string context);
}
class CompletedAwaitTest : ITestInterface
{
public int Length { get; private set; }
public async Task DoAsync(string context)
{
Length = context.Length;
await Task.CompletedTask;
}
}
class CompletedTest : ITestInterface
{
public int Length { get; private set; }
public Task DoAsync(string context)
{
Length = context.Length;
return Task.CompletedTask;
}
}
class PragmaTest : ITestInterface
{
public int Length { get; private set; }
#pragma warning disable 1998
public async Task DoAsync(string context)
{
Length = context.Length;
return;
}
#pragma warning restore 1998
}
class YieldTest : ITestInterface
{
public int Length { get; private set; }
public async Task DoAsync(string context)
{
Length = context.Length;
await Task.Yield();
}
}
public interface ITestInterface2
{
Task<int> DoAsync(string context);
}
class FromResultTest : ITestInterface2
{
public async Task<int> DoAsync(string context)
{
var i = context.Length;
return await Task.FromResult(i);
}
}
}
#pragma
オーバーヘッドが発生するようです。おそらく返すのではなく、ちょうど同じくらいのオーバーヘッドCompletedTask
を作成して完了しましたAsyncOperation
。とにかくメソッドが同期的に実行されるときにそれをスキップしても大丈夫であることをコンパイラに伝えることができればうれしいです。 - binkiTask.CompletedTask
と類似していますTask.FromResult
?知っておくと面白いかもしれません - 値を返す必要がある場合は、FromResultが最も類似していて、それでも最高のパフォーマンスを発揮すると私は思います。 - BlueMonkMN
すでにReactive Extensionにリンクしている場合は、次のこともできます。
public async Task<object> NotImplemented()
{
await Observable.Throw(new NotImplementedException(), null as object).ToTask();
}
public async Task<object> SimpleResult()
{
await Observable.Return(myvalue).ToTask();
}
ReactiveとAsync / awaitはそれ自体でも驚くべきことでもありますが、一緒にうまく機能することもあります。
必要なものは以下のとおりです。
using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;
下記のcs1998が発生する可能性があります。
public async Task<object> Foo()
{
return object;
}
その後、あなたは以下のように改革することができます。
public async Task<object> Foo()
{
var result = await Task.Run(() =>
{
return object;
});
return result;
}
何も待つことがない場合は、Task.FromResultを返してください。
public Task<int> Success() // note: no "async"
{
... // Do not have await code
var result = ...;
return Task.FromResult(result);
}
メソッドシグネチャに応じていくつかの選択肢があります。
public async Task Test1()
{
await Task.CompletedTask;
}
public async Task<object> Test2()
{
return await Task.FromResult<object>(null);
}
public async Task<object> Test3()
{
return await Task.FromException<object>(new NotImplementedException());
}
// This is to get rid of warning CS1998, please remove when implementing this method.
await new Task(() => { }).ConfigureAwait(false);
throw new NotImplementedException();
これを試して:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Await.Warning", "CS1998:Await.Warning")]
メソッドからasyncキーワードを削除して、単にTaskを返すようにすることができます。
public async Task DoTask()
{
State = TaskStates.InProgress;
await RunTimer();
}
public Task RunTimer()
{
return new Task(new Action(() =>
{
using (var t = new time.Timer(RequiredTime.Milliseconds))
{
t.Elapsed += ((x, y) => State = TaskStates.Completed);
t.Start();
}
}));
}