Zaman uyumsuz dönüş türleri (C#)
Zaman uyumsuz yöntemler aşağıdaki dönüş türlerine sahip olabilir:
- Task, bir işlemi gerçekleştiren ancak değer döndüren zaman uyumsuz bir yöntem için.
- Task<TResult>, bir değer döndüren zaman uyumsuz bir yöntem için.
void, bir olay işleyicisi için.- C# 7.0'dan başlayarak, erişilebilir bir yöntemi olan herhangi bir
GetAwaitertür. yöntemi tarafından döndürülen nesneGetAwaiterarabirimini System.Runtime.CompilerServices.ICriticalNotifyCompletion uygulamalı. - Async akışı döndüren zaman uyumsuz bir yöntem için C# 8.0 IAsyncEnumerable<T> ile başlayarak.
Zaman uyumsuz yöntemler hakkında daha fazla bilgi için bkz. Zaman uyumsuz ve await ile zaman uyumsuz programlama (C#).
İş yüklerinin özel olduğu diğer Windows vardır:
- DispatcherOperation, zaman uyumsuz işlemler için Windows.
- IAsyncAction, UWP'de değer dönmeyen zaman uyumsuz eylemler için.
- IAsyncActionWithProgress<TProgress>, UWP'de ilerlemeyi rapor eden ancak bir değer iade eden zaman uyumsuz eylemler için.
- IAsyncOperation<TResult>, UWP'de bir değer dönüşen zaman uyumsuz işlemler için.
- IAsyncOperationWithProgress<TResult,TProgress>, UWP'de ilerlemeyi rapor eden ve bir değer iade eden zaman uyumsuz işlemler için.
Görev dönüş türü
Bir deyimi olmayan veya bir işleneni geri dönmeyen bir deyimi içeren zaman uyumsuz yöntemler return return genellikle dönüş türüne sahip Task olur. Bu tür void yöntemler, zaman uyumlu olarak çalıştırlarısa döner. Zaman uyumsuz bir yöntem için dönüş türü kullanırsanız, çağıran yöntemi çağrılır async yöntemi tamamlandıktan sonra çağıranın tamamlanmasını askıya almak için Task await bir işleç kullanabilir.
Aşağıdaki örnekte yöntemi WaitAndApologizeAsync bir deyimi return içermez, bu nedenle yöntem bir nesnesi Task döndürür. döndürerek Task WaitAndApologizeAsync bekln. TaskTürün bir özelliği yoktur Result çünkü dönüş değeri yoktur.
public static async Task DisplayCurrentInfoAsync()
{
await WaitAndApologizeAsync();
Console.WriteLine($"Today is {DateTime.Now:D}");
Console.WriteLine($"The current time is {DateTime.Now.TimeOfDay:t}");
Console.WriteLine("The current temperature is 76 degrees.");
}
static async Task WaitAndApologizeAsync()
{
await Task.Delay(2000);
Console.WriteLine("Sorry for the delay...\n");
}
// Example output:
// Sorry for the delay...
//
// Today is Monday, August 17, 2020
// The current time is 12:59:24.2183304
// The current temperature is 76 degrees.
WaitAndApologizeAsync , zaman uyumlu void-returning yöntemi için çağrı deyimine benzer şekilde await ifadesi yerine await deyimi kullanılarak beklenen bir ifadedir. Bu durumda await işlecinin uygulaması bir değer üretmez. bir ifadesinin sağ await işleneni bir Task<TResult> olduğunda, await ifadesi bir sonucu T üretir. bir 'nin sağ işleneni await bir Task olduğunda, ve await işleneni bir deyimidir.
Çağrısı, aşağıdaki WaitAndApologizeAsync kodda olduğu gibi await işlecinin uygulamasından ayırabilirsiniz. Ancak, bir özelliğinin olmadığını ve bir await işleci uygulandığında hiçbir değer Task Result üretil olmadığını Task unutmayın.
Aşağıdaki kod yöntemini çağırmayı WaitAndApologizeAsync yönteminin döndür olduğu görevi beklerkenn ayırıyor.
Task waitAndApologizeTask = WaitAndApologizeAsync();
string output =
$"Today is {DateTime.Now:D}\n" +
$"The current time is {DateTime.Now.TimeOfDay:t}\n" +
"The current temperature is 76 degrees.\n";
await waitAndApologizeTask;
Console.WriteLine(output);
Görev <TResult> dönüş türü
Dönüş Task<TResult> türü, işlenenin olduğu bir dönüş deyimi içeren zaman uyumsuz bir yöntem için TResult kullanılır.
Aşağıdaki örnekte yöntemi, GetLeisureHoursAsync tamsayı döndüren return bir deyimi içerir. Yöntem bildirimi bir dönüş türü belirterek Task<int> belirterek. Zaman FromResult uyumsuz yöntem, bir döndüren bir işlem için yer tutucudur. DayOfWeek
public static async Task ShowTodaysInfoAsync()
{
string message =
$"Today is {DateTime.Today:D}\n" +
"Today's hours of leisure: " +
$"{await GetLeisureHoursAsync()}";
Console.WriteLine(message);
}
static async Task<int> GetLeisureHoursAsync()
{
DayOfWeek today = await Task.FromResult(DateTime.Now.DayOfWeek);
int leisureHours =
today is DayOfWeek.Saturday || today is DayOfWeek.Sunday
? 16 : 5;
return leisureHours;
}
// Example output:
// Today is Wednesday, May 24, 2017
// Today's hours of leisure: 5
yönteminde bir await ifadesinin içinde çağrıldı mı, await ifadesi yöntemi tarafından döndürülen görevde depolanan tamsayı değerini GetLeisureHoursAsync ShowTodaysInfo leisureHours (değeri) GetLeisureHours döndürür. await ifadeleri hakkında daha fazla bilgi için bkz. await.
Aşağıdaki kodda da olduğu gibi çağrısını uygulamasından ayırarak sonucun bir'den nasıl await Task<T> GetLeisureHoursAsync await alınarak elde edilen sonucu daha iyi anabilirsiniz. Hemen GetLeisureHoursAsync beklemeden yöntemine yapılan bir çağrı, yönteminin Task<int> bildiriminden beklediğiniz gibi bir döndürür. Görev örnekteki getLeisureHoursTask değişkenine atanır. bir getLeisureHoursTask olduğundan türünde bir özelliği Task<TResult> Result TResult içerir. Bu durumda, bir TResult tamsayı türünü temsil eder. için await uygulandığında getLeisureHoursTask await ifadesi özelliğinin içeriğine Result göre getLeisureHoursTask değerlendirilir. değeri değişkenine ret atanır.
Önemli
özelliği Result bir engelleme özelliğidir. Görevi bitmeden önce bu iş parçacığına erişmeye çalışsanız, görev tamamlandıktan ve değer kullanılabilir olana kadar o anda etkin olan iş parçacığı engellenir. Çoğu durumda, özelliğine doğrudan erişmek yerine await kullanarak değere erişmelisiniz.
Önceki örnek, uygulama sona ermeden önce yönteminin konsola yazdırılana kadar ana iş parçacığını engellemek Result Main için message özelliğinin değerini alınmıştı.
var getLeisureHoursTask = GetLeisureHoursAsync();
string message =
$"Today is {DateTime.Today:D}\n" +
"Today's hours of leisure: " +
$"{await getLeisureHoursTask}";
Console.WriteLine(message);
Void dönüş türü
Dönüş void türünü, dönüş türü gerektiren zaman uyumsuz olay işleyicileri içinde void kullanırsiniz. Değer döndüren olay işleyicileri dışında yöntemler için, döndüren zaman uyumsuz bir yöntem beklenmemiş olduğundan bunun yerine bir Task void döndürebilirsiniz. Bu tür bir yöntemin çağıranları, çağrılır async yönteminin bitip bitmeden tamamlanmaya devam edecektir. Çağıranın, zaman uyumsuz yöntemin oluşturt olduğu değerlerden veya özel durumlardan bağımsız olması gerekir.
Void döndüren zaman uyumsuz yöntemin çağıranı, yönteminden ortaya atılan özel durumları yakalayamaz. İşlenemeyen bu tür özel durumlar, büyük olasılıkla uygulamanın başarısız olmasına neden olur. Veya döndüren bir yöntem Task Task<TResult> özel durum oluşturursa, özel durum döndürülen görev içinde depolanır. Görev beklediği zaman özel durum yeniden atlandı. Özel durum üretenin herhangi bir zaman uyumsuz yöntemin veya dönüş türüne sahip olduğundan ve Task Task<TResult> yöntemine yapılan çağrıların beklenilenden emin olun.
Zaman uyumsuz yöntemlerde özel durumları yakalama hakkında daha fazla bilgi için try-catch makalenin Zaman uyumsuz yöntemler bölümündeki Özel Durumlar bölümüne bakın.
Aşağıdaki örnek, zaman uyumsuz olay işleyicinin davranışını gösterir. Örnek kodda, zaman uyumsuz bir olay işleyicisi, ana iş parçacığının ne zaman bitip bitse bunu haber vermesi gerekir. Ardından ana iş parçacığı, programdan çıkmadan önce zaman uyumsuz olay işleyicisini bekleyebilir.
using System;
using System.Threading.Tasks;
public class NaiveButton
{
public event EventHandler? Clicked;
public void Click()
{
Console.WriteLine("Somebody has clicked a button. Let's raise the event...");
Clicked?.Invoke(this, EventArgs.Empty);
Console.WriteLine("All listeners are notified.");
}
}
public class AsyncVoidExample
{
static readonly TaskCompletionSource<bool> s_tcs = new TaskCompletionSource<bool>();
public static async Task MultipleEventHandlersAsync()
{
Task<bool> secondHandlerFinished = s_tcs.Task;
var button = new NaiveButton();
button.Clicked += OnButtonClicked1;
button.Clicked += OnButtonClicked2Async;
button.Clicked += OnButtonClicked3;
Console.WriteLine("Before button.Click() is called...");
button.Click();
Console.WriteLine("After button.Click() is called...");
await secondHandlerFinished;
}
private static void OnButtonClicked1(object? sender, EventArgs e)
{
Console.WriteLine(" Handler 1 is starting...");
Task.Delay(100).Wait();
Console.WriteLine(" Handler 1 is done.");
}
private static async void OnButtonClicked2Async(object? sender, EventArgs e)
{
Console.WriteLine(" Handler 2 is starting...");
Task.Delay(100).Wait();
Console.WriteLine(" Handler 2 is about to go async...");
await Task.Delay(500);
Console.WriteLine(" Handler 2 is done.");
s_tcs.SetResult(true);
}
private static void OnButtonClicked3(object? sender, EventArgs e)
{
Console.WriteLine(" Handler 3 is starting...");
Task.Delay(100).Wait();
Console.WriteLine(" Handler 3 is done.");
}
}
// Example output:
//
// Before button.Click() is called...
// Somebody has clicked a button. Let's raise the event...
// Handler 1 is starting...
// Handler 1 is done.
// Handler 2 is starting...
// Handler 2 is about to go async...
// Handler 3 is starting...
// Handler 3 is done.
// All listeners are notified.
// After button.Click() is called...
// Handler 2 is done.
Genelleştirilmiş zaman uyumsuz dönüş türleri ve ValueTask<TResult>
C# 7.0'dan başlayarak, zaman uyumsuz bir yöntem, bekleyen türünün bir örneğini döndüren erişilebilir bir yöntemi olan GetAwaiter herhangi bir türü döndürebilirsiniz. Ayrıca, yönteminden döndürülen GetAwaiter türün özniteliğine sahip olması System.Runtime.CompilerServices.AsyncMethodBuilderAttribute gerekir. Derleyici tarafından okunan öznitelikler veya dönüş türleri gibi Görev için özellik özellikleri makalesinde daha fazla bilgi bulabilirsiniz.
Bu özellik, işleneni için gereksinimleri açıklayan,beklenebilir ifadeleri tamamlayıcı niteliktedir. await Genelleştirilmiş zaman uyumsuz dönüş türleri, derleyicinin farklı async türler üreten yöntemler oluşturmalarını sağlar. .NET kitaplıklarında genelleştirilmiş zaman uyumsuz dönüş türleri performans geliştirmelerini etkinleştirdi. ve başvuru türleri olduğundan, özellikle de sıkı döngülerde ayırmalar oluştuğunda performans açısından kritik yollarda bellek ayırma performansı Task Task<TResult> olumsuz etkileyebilir. Genelleştirilmiş dönüş türleri için destek, ek bellek ayırmalarını önlemek için başvuru türü yerine basit bir değer türü getirtmek anlamına gelir.
.NET, System.Threading.Tasks.ValueTask<TResult> genelleştirilmiş bir görev döndüren değerin basit bir uygulaması olarak yapısını sağlar. Türünü kullanmak System.Threading.Tasks.ValueTask<TResult> için projenize NuGet System.Threading.Tasks.Extensions eklemeniz gerekir. Aşağıdaki örnek, iki ValueTask<TResult> zar atması değerini almak için yapısını kullanır.
using System;
using System.Threading.Tasks;
class Program
{
static readonly Random s_rnd = new Random();
static async Task Main() =>
Console.WriteLine($"You rolled {await GetDiceRollAsync()}");
static async ValueTask<int> GetDiceRollAsync()
{
Console.WriteLine("Shaking dice...");
int roll1 = await RollAsync();
int roll2 = await RollAsync();
return roll1 + roll2;
}
static async ValueTask<int> RollAsync()
{
await Task.Delay(500);
int diceRoll = s_rnd.Next(1, 7);
return diceRoll;
}
}
// Example output:
// Shaking dice...
// You rolled 8
Genelleştirilmiş bir zaman uyumsuz dönüş türü yazmak gelişmiş bir senaryodur ve özelleştirilmiş ortamlarda kullanım için hedeftir. Bunun Task yerine, zaman uyumsuz kod için çoğu senaryoyu kapsayacak şekilde , ve Task<T> türlerini kullanmayı göz ValueTask<T> önünde bulundurabilirsiniz.
C# 10 ve üzerinde, oluşturucusu bu tür için geçersiz kılmak için özniteliğini zaman uyumsuz bir yönteme (zaman uyumsuz dönüş türü bildirimi AsyncMethodBuilder yerine) uygulayabilirsiniz. Genellikle bu özniteliği .NET çalışma zamanında sağlanan farklı bir oluşturucu kullanmak için uygulayabilirsiniz.
IAsyncEnumerable ile zaman uyumsuz akışlar<T>
C# 8.0'dan başlayarak, zaman uyumsuz bir yöntem ile temsil edilen bir zaman uyumsuz akış dönüşe neden IAsyncEnumerable<T> olabilir. Zaman uyumsuz akış, öğeler yinelenen zaman uyumsuz çağrılara sahip öbekler halinde üretilen bir akıştan okunan öğeleri numaralandıracak bir yol sağlar. Aşağıdaki örnek, zaman uyumsuz akış oluşturan zaman uyumsuz bir yöntemi gösterir:
static async IAsyncEnumerable<string> ReadWordsFromStreamAsync()
{
string data =
@"This is a line of text.
Here is the second line of text.
And there is one more for good measure.
Wait, that was the penultimate line.";
using var readStream = new StringReader(data);
string line = await readStream.ReadLineAsync();
while (line != null)
{
foreach (string word in line.Split(' ', StringSplitOptions.RemoveEmptyEntries))
{
yield return word;
}
line = await readStream.ReadLineAsync();
}
}
Yukarıdaki örnek, bir dizeden satırları zaman uyumsuz olarak okur. Her satır okunduktan sonra kod, dizede her sözcüğü numaralar. Çağıranlar deyimini kullanarak her sözcüğü await foreach numaralar. yöntemi, kaynak dizeden sonraki satırı zaman uyumsuz olarak okuması gerekenleri bekler.