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.

  1. İndirilen sıkıştırılmış dosyayı açın ve sonra Visual Studio'yu başlatın.

  2. Menü çubuğunda, Dosya, , Proje/Çözüm seçeneklerini belirleyin.

  3. 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:

  1. Visual Studio'yu başlatın.

  2. Menü çubuğunda Dosya, Yeni, Proje seçeneğini belirleyin.

    Yeni Proje iletişim kutusu açılır.

  3. Yüklü Şablonlar bömesinde Visual Basic veya Visual C# seçin ve ardından proje türleri listesinden WPF Uygulamasıöğesini seçin.

  4. Projenin adı olarak AsyncTracer girin ve sonra Tamam düğmesini seçin.

    Çözüm Gezgini içinde yeni proje görüntülenir.

  5. 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.

  6. 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&#xa;" 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.

  7. System.Net.Http başvurusu ekleyin.

  8. Çö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.

  9. 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;
            }
        }
    }
    
  10. 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.

Birinci ve ikinci adımları

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.

ÜÇ adım

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.

Adım dört

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.

BEŞ adım

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.

Adım altı

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ışı