Zaman Uyumsuz Programlarda Denetim Akışı (C# ve Visual Basic)
Async ve Await anahtar sözcüklerini kullanarak zaman uyumsuz programları daha kolay şekilde yazabilir ve koruyabilirsiniz.Ancak programınızın nasıl çalıştığını anlamazsanız sonuçlar sizi şaşırtabilir.Bu konu, kontrolün bir yöntemden diğerine ne zaman taşındığını ve her seferinde hangi bilgilerin aktarıldığını size göstermek için, basit bir zamanuyumsuz program içinde kontrol akışını izler.
[!NOT]
Async ve Await anahtar sözcükleri Visual Studio 2012'de kullanılmaya başlanmıştır.
Genel olarak, Zaman Uyumsuz (Visual Basic) veya async (C#) değiştiriciyle zaman uyumsuz kodun yer aldığı yöntemleri işaretlersiniz.Zaman uyumsuz değiştiriciyle işaretlenmiş bir yöntemde, tamamlanacak zaman uyumsuz işlem için metodun bekletmek üzere nerede duraklatacağını belirtmek için Await (Visual Basic) veya await (C#) işlecini kullanabilirsiniz.Daha fazla bilgi için bkz. Async ve Await ile Zaman Uyumsuz Programlama (C# ve Visual Basic).
Aşağıdaki örnek, bir dize olarak belirtilen bir Web sitesinin içeriği karşıdan yüklemek ve dizenin uzunluğu görüntülemek için zaman uyumsuz yöntemleri kullanır.Örnek aşağıdaki iki yöntemi içerir.
startButton_Click, AccessTheWebAsync çağırır ve sonucu görüntüler.
Bir web sitesinin içeriklerini dize olarak karşıdan yükleyen ve dizenin uzunluğunu getiren AccessTheWebAsync.AccessTheWebAsync, içerikleri karşıdan yüklemek için zaman uyumsuz bir HttpClient yöntemini (GetStringAsync(String)) kullanır.
Numaralı ekran satırları, programın nasıl çalıştığını anlamanıza yardımcı olmak ve işaretlenmiş her noktada neler olduğunu açıklamak için program boyunca stratejik noktalarda görüntülenir.Görüntü satırları "BİR" ve "ALTI" arasında etiketlenir. Etiketler, programın bu kod satırlarına hangi sırayla ulaştığını temsil eder.
Aşağıdaki kod, programın özetini gösterir.
Class MainWindow
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click
' ONE
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
' FOUR
Dim contentLength As Integer = Await getLengthTask
' SIX
ResultsTextBox.Text &=
String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength)
End Sub
Async Function AccessTheWebAsync() As Task(Of Integer)
' TWO
Dim client As HttpClient = New HttpClient()
Dim getStringTask As Task(Of String) =
client.GetStringAsync("https://msdn.microsoft.com")
' THREE
Dim urlContents As String = Await getStringTask
' FIVE
Return urlContents.Length
End Function
End Class
public partial class MainWindow : Window
{
// . . .
private async void startButton_Click(object sender, RoutedEventArgs e)
{
// ONE
Task<int> getLengthTask = AccessTheWebAsync();
// FOUR
int contentLength = await getLengthTask;
// SIX
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
async Task<int> AccessTheWebAsync()
{
// TWO
HttpClient client = new HttpClient();
Task<string> getStringTask =
client.GetStringAsync("https://msdn.microsoft.com");
// THREE
string urlContents = await getStringTask;
// FIVE
return urlContents.Length;
}
}
"ONE" ila "SIX" arasındaki etiketli konumların her biri, programın geçerli durumuyla ilgili bilgileri görüntüler.Aşağıdaki çıktı üretilmiştir.
ONE: Entering startButton_Click.
Calling AccessTheWebAsync.
TWO: Entering AccessTheWebAsync.
Calling HttpClient.GetStringAsync.
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
SIX: Back in startButton_Click.
Task getLengthTask is finished.
Result from AccessTheWebAsync is stored in contentLength.
About to display contentLength and exit.
Length of the downloaded string: 33946.
Program Ayarlama
Bu konuda kullanan kodu MSDN sitesinden yükleyebilir veya kodu kendiniz oluşturabilirsiniz.
[!NOT]
Örneği çalıştırmak için, bilgisayarınızda Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012, Windows için Visual Studio Express 2013 veya .NET Framework 4.5 veya 4.5.1 yüklü olmalıdır.
Programı Karşıdan Yükleme
Bu konu için uygulamayı Zamanuyumsuz Örneği: Zamanuyumsuz Programlarda Akış Kontrolü kaynağından indirebilirsiniz.Aşağıdaki adımlar programı açar ve çalıştırır.
İndirilen sıkıştırılmış dosyayı açın ve sonra Visual Studio'yu başlatın.
Menü çubuğunda, Dosya, Aç, Proje/Çözüm seçeneklerini belirleyin.
Sıkıştırması açılmış örnek kodun bulunduğu klasöre gidin ve projeyi derlemek ve çalıştırmak için F5 tuşunu seçin.
Programı Kendiniz Oluşturun
Aşağıdaki Windows Presentation Foundation (WPF) projesi bu konu için kod örneğini içermektedir.
Projeyi çalıştırmak için aşağıdaki adımları gerçekleştirin:
Visual Studio'yu başlatın.
Menü çubuğunda Dosya, Yeni, Proje seçeneğini belirleyin.
Yeni Proje iletişim kutusu açılır.
Yüklü Şablonlar bömesinde Visual Basic veya Visual C# seçin ve ardından proje türleri listesinden WPF Uygulamasıöğesini seçin.
Projenin adı olarak AsyncTracer girin ve sonra Tamam düğmesini seçin.
Çözüm Gezgini içinde yeni proje görüntülenir.
Visual Studio Kod Düzenleyicisi'nde MainWindow.xaml sekmesini seçin.
Sekme görünür değilse, Çözüm Gezgini'nde MainWindow.xaml için kısayol menüsünü açın ve Kodu Görüntüle'yi seçin.
MainWindow.xaml XAML görünümünde kodu aşağıdaki kodla değiştirin.
<Window xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MainWindow" Title="Control Flow Trace" Height="350" Width="525"> <Grid> <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="221,10,0,0" VerticalAlignment="Top" Width="75"/> <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Bottom" Width="510" Height="265" FontFamily="Lucida Console" FontSize="10" VerticalScrollBarVisibility="Visible" d:LayoutOverrides="HorizontalMargin"/> </Grid> </Window>
<Window xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="AsyncTracer.MainWindow" Title="Control Flow Trace" Height="350" Width="592"> <Grid> <Button x:Name="startButton" Content="Start
" HorizontalAlignment="Left" Margin="250,10,0,0" VerticalAlignment="Top" Width="75" Height="24" Click="startButton_Click" d:LayoutOverrides="GridBox"/> <TextBox x:Name="resultsTextBox" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Bottom" Width="576" Height="265" FontFamily="Lucida Console" FontSize="10" VerticalScrollBarVisibility="Visible" Grid.ColumnSpan="3"/> </Grid> </Window>
Bir metin kutusu ve MainWindow.xaml öğesinin Design görünümünde görünen bir düğme içeren basit bir pencere.
System.Net.Http başvurusu ekleyin.
Çözüm Gezgini içinde MainWindow.xaml.vb veya MainWindow.xaml.cs kısayol menüsünü açın ve Kodu Görüntüle öğesini seçin.
MainWindow.xaml.vb veya MainWindow.xaml.cs dosyasındaki kodu aşağıdaki kodla değiştirin.
' Add an Imports statement and a reference for System.Net.Http. Imports System.Net.Http Class MainWindow Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click ' The display lines in the example lead you through the control shifts. ResultsTextBox.Text &= "ONE: Entering StartButton_Click." & vbCrLf & " Calling AccessTheWebAsync." & vbCrLf Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync() ResultsTextBox.Text &= vbCrLf & "FOUR: Back in StartButton_Click." & vbCrLf & " Task getLengthTask is started." & vbCrLf & " About to await getLengthTask -- no caller to return to." & vbCrLf Dim contentLength As Integer = Await getLengthTask ResultsTextBox.Text &= vbCrLf & "SIX: Back in StartButton_Click." & vbCrLf & " Task getLengthTask is finished." & vbCrLf & " Result from AccessTheWebAsync is stored in contentLength." & vbCrLf & " About to display contentLength and exit." & vbCrLf ResultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength) End Sub Async Function AccessTheWebAsync() As Task(Of Integer) ResultsTextBox.Text &= vbCrLf & "TWO: Entering AccessTheWebAsync." ' Declare an HttpClient object. Dim client As HttpClient = New HttpClient() ResultsTextBox.Text &= vbCrLf & " Calling HttpClient.GetStringAsync." & vbCrLf ' GetStringAsync returns a Task(Of String). Dim getStringTask As Task(Of String) = client.GetStringAsync("https://msdn.microsoft.com") ResultsTextBox.Text &= vbCrLf & "THREE: Back in AccessTheWebAsync." & vbCrLf & " Task getStringTask is started." ' AccessTheWebAsync can continue to work until getStringTask is awaited. ResultsTextBox.Text &= vbCrLf & " About to await getStringTask & return a Task(Of Integer) to StartButton_Click." & vbCrLf ' Retrieve the website contents when task is complete. Dim urlContents As String = Await getStringTask ResultsTextBox.Text &= vbCrLf & "FIVE: Back in AccessTheWebAsync." & vbCrLf & " Task getStringTask is complete." & vbCrLf & " Processing the return statement." & vbCrLf & " Exiting from AccessTheWebAsync." & vbCrLf Return urlContents.Length End Function End Class
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; // Add a using directive and a reference for System.Net.Http; using System.Net.Http; namespace AsyncTracer { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void startButton_Click(object sender, RoutedEventArgs e) { // The display lines in the example lead you through the control shifts. resultsTextBox.Text += "ONE: Entering startButton_Click.\r\n" + " Calling AccessTheWebAsync.\r\n"; Task<int> getLengthTask = AccessTheWebAsync(); resultsTextBox.Text += "\r\nFOUR: Back in startButton_Click.\r\n" + " Task getLengthTask is started.\r\n" + " About to await getLengthTask -- no caller to return to.\r\n"; int contentLength = await getLengthTask; resultsTextBox.Text += "\r\nSIX: Back in startButton_Click.\r\n" + " Task getLengthTask is finished.\r\n" + " Result from AccessTheWebAsync is stored in contentLength.\r\n" + " About to display contentLength and exit.\r\n"; resultsTextBox.Text += String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength); } async Task<int> AccessTheWebAsync() { resultsTextBox.Text += "\r\nTWO: Entering AccessTheWebAsync."; // Declare an HttpClient object. HttpClient client = new HttpClient(); resultsTextBox.Text += "\r\n Calling HttpClient.GetStringAsync.\r\n"; // GetStringAsync returns a Task<string>. Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com"); resultsTextBox.Text += "\r\nTHREE: Back in AccessTheWebAsync.\r\n" + " Task getStringTask is started."; // AccessTheWebAsync can continue to work until getStringTask is awaited. resultsTextBox.Text += "\r\n About to await getStringTask and return a Task<int> to startButton_Click.\r\n"; // Retrieve the website contents when task is complete. string urlContents = await getStringTask; resultsTextBox.Text += "\r\nFIVE: Back in AccessTheWebAsync." + "\r\n Task getStringTask is complete." + "\r\n Processing the return statement." + "\r\n Exiting from AccessTheWebAsync.\r\n"; return urlContents.Length; } } }
Programı çalıştırmak için F5 tuşuna basın ve sonra Başlat düğmesine basın.
Aşağıdaki çıktı görünmelidir.
ONE: Entering startButton_Click. Calling AccessTheWebAsync. TWO: Entering AccessTheWebAsync. Calling HttpClient.GetStringAsync. THREE: Back in AccessTheWebAsync. Task getStringTask is started. About to await getStringTask & return a Task<int> to startButton_Click. FOUR: Back in startButton_Click. Task getLengthTask is started. About to await getLengthTask -- no caller to return to. FIVE: Back in AccessTheWebAsync. Task getStringTask is complete. Processing the return statement. Exiting from AccessTheWebAsync. SIX: Back in startButton_Click. Task getLengthTask is finished. Result from AccessTheWebAsync is stored in contentLength. About to display contentLength and exit. Length of the downloaded string: 33946.
Programı İzle
BİR ve İKİNCİ adımlar
İlk iki görüntü satırı yolu startButton_Click çağrılar olarak izler AccessTheWebAsync ve AccessTheWebAsync zaman uyumsuz HttpClient yöntemini çağırır GetStringAsync(String).Aşağıdaki resimde yöntemden yönteme çağrılar özetlenmektedir.
Hem AccessTheWebAsync hem de client.GetStringAsync öğelerinin dönüş türü Task öğesidir.AccessTheWebAsync için TResult bir tamsayıdır.GetStringAsynciçin TResult bir dizedir.Zaman uyumsuz yöntem dönüş türleri hakkında daha fazla bilgi için bkz. Zaman Uyumsuz Dönüş Türleri (C# ve Visual Basic).
Görev döndüren zaman uyumsuz yöntem, denetim arayana geri geçtiğinde bir görev örneği getirir.Çağrılan yöntemde bir Await veya await işleciyle karşılaşıldığında ya da çağrılan yöntem sona erdiğinde çağırana zaman uyumsuz bir yöntemden denetim getirilir.Etiketleri "ÜÇ" ile "ALTI" arasındaki görüntü satırları işlemin bu parçasını izler.
Adım ÜÇ
AccessTheWebAsync içinde, GetStringAsync(String) zaman uyumsuz yöntemi hedef web sayfasının içeriğini indirmek için çağrılır.client.GetStringAsync getirildiğinde client.GetStringAsync öğesinden AccessTheWebAsync öğesine denetim getirilir.
client.GetStringAsync Yöntemi, AccessTheWebAsync içindeki getStringTask değişkene atanan bir dize görevini döndürür.Örnek programdaki aşağıdaki satır client.GetStringAsync çağrısı ve atamayı göstermektedir.
Dim getStringTask As Task(Of String) = client.GetStringAsync("https://msdn.microsoft.com")
Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com");
Görevi, client.GetStringAsync öğesinin sonuçta gerçek bir dize oluşturma hedefi olarak düşünebilirsiniz.Bu sırada, AccessTheWebAsync, client.GetStringAsync kaynaklı taahhüt edilen dizeden bağımsız yapılacak çalışmaya sahipse, bu çalışma client.GetStringAsync beklediği sürece devam eder.Örnekte, "ÜÇ" etiketli aşağıdaki çıktı satırları bağımsız iş yapma fırsatını göstermektedir
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
Aşağıdaki deyim getStringTask beklendiğinde AccessTheWebAsync öğesinin ilerlemesini askıya alır.
Dim urlContents As String = Await getStringTask
string urlContents = await getStringTask;
Aşağıdaki resimde client.GetStringAsync öğesinden getStringTask atamaya ve getStringTask oluşturmadan bir await işlecinin uygulamasına kadar denetim akışı gösterilmektedir.
Await ifadesi client.GetStringAsync döndürülünceye kadar AccessTheWebAsync öğesini askıya alır.Bu sırada denetim, zaman uyumsuz AccessTheWebAsync, startButton_Click yöntemini çağırana döner.
[!NOT]
Genellikle, zamanuyumsuz bir yönteme yapılacak çağrıyı hemen bekletirsiniz.Örneğin, aşağıdaki atamalardan biri, getStringTask öğesini oluşturan ve sonra bekleyen önceki kodun yerini alabilir:
Visual Basic: Dim urlContents As String = Await client.GetStringAsync("https://msdn.microsoft.com")
C#: string urlContents = await client.GetStringAsync("https://msdn.microsoft.com");
Bu konuda, await işleci, program içinde denetim akışını işaretleyen çıkış satırlarını yerleştirmek için daha sonra uygulanır.
DÖRDÜNCÜ Adım
Bildirilen AccessTheWebAsync dönüş türü Visual Basic'te Task(Of Integer) ve C#'de Task<int> türleridir.Bu nedenle, AccessTheWebAsync askıya alındığı zaman, startButton_Click öğesine bir tamsayı görevi döndürür.Döndürülen görevin getStringTask olmadığını anlamlısınız.Döndürülen görev, AccessTheWebAsync askıya alınmış yönteminde diğer yapılması gerekenleri gösteren yeni bir tamsayı görevidir.Görev, görev tamamlandığında bir tamsayı üretmek için AccessTheWebAsync öğesinin bir vaadidir.
Aşağıdaki deyim, bu görevi getLengthTask değişkenine atar.
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
Task<int> getLengthTask = AccessTheWebAsync();
AccessTheWebAsync içinde olduğu gibi startButton_Click, görev bekleninceye kadar zaman uyumsuz görevin (getLengthTask) sonucuna bağlı olmadan çalışmaya devam edebilir.Aşağıdaki çıktı satırları bu işi temsil eder.
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
startButton_Click'deki ilerlemeniz getLengthTask beklendiği zaman askıya alınır.Aşağıdaki atama deyimi AccessTheWebAsync tamamlanana kadar startButton_Click öğesini askıya alır.
Dim contentLength As Integer = Await getLengthTask
int contentLength = await getLengthTask;
Aşağıdaki çizimde, oklar AccessTheWebAsync seçeneğindeki await ifadesine ait denetim akışını değer atamasına gösteriyor; getLengthTask, startButton_Click seçeneğinde getLengthTask bekleyene kadar normal işlem tarafından beklenir.
BEŞİNCİ Adım
client.GetStringAsync tamamlandığı sinyalini verdiğinde, AccessTheWebAsync içindeki işlem askıda durumundan çıkarılır ve bekleme ifadesinin ötesine devam edebilir.Aşağıdaki çıktı satırları işlemin sürdürülmesini temsil etmektedir.
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
Return ifadesinin işleneni olan urlContents.Length, AccessTheWebAsync öğesinin döndürdüğü görevde depolanır.await ifadesi bu değeri startButton_Click içindeki getLengthTask öğesinden alır.
Aşağıdaki resimde client.GetStringAsync (ve getStringTask) tamamlandıktan sonraki denetim aktarımı gösterilmektedir.
AccessTheWebAsync, tamamlanıncaya kadar çalışır ve tamamlanmayı bekleyen startButton_Click öğesine dönüşleri denetler.
ALTINCI Adım
AccessTheWebAsync tamamlandığı sinyalini verirse, işlem startButton_Async içindeki bekleme ifadesinin ötesine devam edebilir.Aslında, programın yapacak başka bir şeyi de yoktur.
Aşağıdaki çıktı satırları startButton_Async içinde işlemin sürdürülmesini temsil etmektedir:
SIX: Back in startButton_Click.
Task getLengthTask is finished.
Result from AccessTheWebAsync is stored in contentLength.
About to display contentLength and exit.
Await ifadesi, AccessTheWebAsync içindeki return deyiminin işleneni olan getLengthTask tamsayı değerinden alınır.Aşağıdaki deyim, bu değeri contentLength değişkenine atar.
Dim contentLength As Integer = Await getLengthTask
int contentLength = await getLengthTask;
Aşağıdaki resimde AccessTheWebAsync öğesinden startButton_Click öğesine kadar denetimin dönüşü gösterilmektedir.
Ayrıca bkz.
Görevler
İzlenecek yol: Async ve Await Kullanarak Web'e Erişme (C# ve Visual Basic)
İzlenecek Yol: Hata Ayıklayıcıyı Zaman Uyumsuz Yöntemlerle Kullanma
Kavramlar
Async ve Await ile Zaman Uyumsuz Programlama (C# ve Visual Basic)
Zaman Uyumsuz Dönüş Türleri (C# ve Visual Basic)
Diğer Kaynaklar
Zaman Uyumsuz Örneği: Zaman Uyumsuz Programlarda (C# ve Visual Basic) Denetim Akışı