Megosztás a következőn keresztül:


Az eseményalapú aszinkron minta implementálása

Ha olyan osztályt ír, amely néhány olyan művelettel rendelkezik, amely jelentős késéseket okozhat, fontolja meg az aszinkron funkciók megadását az eseményalapú aszinkron minta implementálásával.

Az eseményalapú aszinkron minta szabványosított módot biztosít az aszinkron funkciókkal rendelkező osztályok csomagolására. Ha olyan segédosztályokkal van implementálva, mint például AsyncOperationManager, az osztály minden alkalmazásmodellben megfelelően fog működni, beleértve a ASP.NET, a konzolalkalmazásokat és a Windows Forms-alkalmazásokat.

Az eseményalapú aszinkron mintát megvalósító példa: Útmutató: Az eseményalapú aszinkron mintát támogató összetevő implementálása.

Az egyszerű aszinkron műveletekhez megfelelőnek találhatja az összetevőt BackgroundWorker . További információBackgroundWorker: Művelet futtatása a háttérben.

Az alábbi lista a jelen témakörben tárgyalt eseményalapú aszinkron minta funkcióit ismerteti.

  • Az eseményalapú aszinkron minta implementálásának lehetőségei

  • Aszinkron metódusok elnevezése

  • Opcionálisan a lemondás támogatása

  • Opcionálisan az IsBusy tulajdonság támogatása

  • Opcionálisan támogatás biztosítása a folyamatjelentéshez

  • Igény szerint támogatás megadása növekményes eredmények visszaadására

  • Out and Ref Parameters in Methods (Out and Ref Parameters in Methods) kezelése

Az eseményalapú aszinkron minta implementálásának lehetőségei

Fontolja meg az eseményalapú aszinkron minta implementálását, ha:

  • Az osztály ügyfeleinek nincs szükségük WaitHandle az IAsyncResult aszinkron műveletekhez elérhető objektumokra, ami azt jelenti, hogy a lekérdezést WaitAll az ügyfélnek kell létrehoznia, vagy WaitAny létre kell állítania.

  • Azt szeretné, hogy az aszinkron műveleteket az ügyfél felügyelje a jól ismert esemény-/delegálási modellel.

Minden művelet az aszinkron implementáció egyik jelöltje, de figyelembe kell venni azokat, amelyek hosszú késéssel járnak. Különösen megfelelőek azok a műveletek, amelyekben az ügyfelek metódust hívnak meg, és a befejezéskor értesítést kapnak, további beavatkozás nélkül. Megfelelőek azok a műveletek is, amelyek folyamatosan futnak, és rendszeres időközönként értesítik az ügyfeleket az előrehaladásról, a növekményes eredményekről vagy az állapotváltozásokról.

Az eseményalapú aszinkron minta támogatásának időpontjáról további információt az eseményalapú aszinkron minta implementálásának időpontjáról szóló témakörben talál.

Aszinkron metódusok elnevezése

Minden olyan szinkron metódushoz, amelyhez aszinkron megfelelőt szeretne megadni:

Adjon meg egy MethodNameAsync metódust, amely:

  • A visszaadott érték.void

  • Ugyanazokat a paramétereket veszi fel, mint a MethodName metódus.

  • Több meghívást fogad el.

Igény szerint a MethodName Async paraméterrel azonos MethodNameAsync-túlterhelést is definiálhat, de egy további objektumértékkel rendelkező paraméterrel, az úgynevezett .userState Ezt akkor tegye, ha készen áll a metódus több egyidejű meghívásának kezelésére, ebben az esetben az userState érték vissza lesz adva az összes eseménykezelőnek a metódus meghívásainak megkülönböztetése érdekében. Dönthet úgy is, hogy ezt egyszerűen a felhasználói állapot későbbi lekéréses tárolására szolgáló helyként teszi meg.

Minden különálló MethodNameAsync metódus-aláírás esetében:

  1. Adja meg a következő eseményt ugyanabban az osztályban, mint a metódus:

    Public Event MethodNameCompleted As MethodNameCompletedEventHandler
    
    public event MethodNameCompletedEventHandler MethodNameCompleted;
    
  2. Adja meg a következő delegáltat és AsyncCompletedEventArgs. Ezek valószínűleg az osztályon kívül lesznek definiálva, de ugyanabban a névtérben.

    Public Delegate Sub MethodNameCompletedEventHandler( _
        ByVal sender As Object, _
        ByVal e As MethodNameCompletedEventArgs)
    
    Public Class MethodNameCompletedEventArgs
        Inherits System.ComponentModel.AsyncCompletedEventArgs
    Public ReadOnly Property Result() As MyReturnType
    End Property
    
    public delegate void MethodNameCompletedEventHandler(object sender,
        MethodNameCompletedEventArgs e);
    
    public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
    {
        public MyReturnType Result { get; }
    }
    
    • Győződjön meg arról, hogy a MethodNameCompletedEventArgs osztály írásvédett tulajdonságként, nem mezőként teszi elérhetővé tagjait, mivel a mezők megakadályozzák az adatkötést.

    • Ne definiáljon AsyncCompletedEventArgs-származtatott osztályokat olyan metódusokhoz, amelyek nem hoznak létre eredményt. Egyszerűen használjon saját példányt AsyncCompletedEventArgs .

      Feljegyzés

      A delegáltak és típusok újrafelhasználása – ha lehetséges és AsyncCompletedEventArgs megfelelő – tökéletesen elfogadható. Ebben az esetben az elnevezés nem lesz összhangban a metódus nevével, mivel egy adott meghatalmazott AsyncCompletedEventArgs nem lesz egyetlen metódushoz kötve.

Opcionálisan a lemondás támogatása

Ha az osztály támogatja az aszinkron műveletek megszakítását, a lemondást az alábbiak szerint közzé kell tenni az ügyfél számára. A lemondási támogatás meghatározása előtt két döntési pontot kell elérni:

  • Az osztálynak, beleértve a jövőbeli várható kiegészítéseket is, csak egy aszinkron művelettel rendelkezik, amely támogatja a lemondást?
  • A lemondást támogató aszinkron műveletek támogathatnak több függőben lévő műveletet? Ez azt jelenti, hogy a MethodNameAsync metódus használ egy paramétert userState , és engedélyezi a több meghívást, mielőtt várnia kell a befejezésre?

Az alábbi táblázatban szereplő két kérdésre adott válaszok segítségével meghatározhatja, hogy mi legyen a lemondási módszer aláírása.

Visual Basic

Több egyidejű művelet támogatott Egyszerre csak egy művelet
Egy aszinkron művelet a teljes osztályban Sub MethodNameAsyncCancel(ByVal userState As Object) Sub MethodNameAsyncCancel()
Több Async-művelet az osztályban Sub CancelAsync(ByVal userState As Object) Sub CancelAsync()

C#

Több egyidejű művelet támogatott Egyszerre csak egy művelet
Egy aszinkron művelet a teljes osztályban void MethodNameAsyncCancel(object userState); void MethodNameAsyncCancel();
Több Async-művelet az osztályban void CancelAsync(object userState); void CancelAsync();

Ha megadja a metódust, az CancelAsync(object userState) ügyfeleknek óvatosnak kell lenniük az állapotértékek kiválasztásakor, hogy képesek legyenek megkülönböztetni az objektumon meghívott összes aszinkron metódust, és nem csak egyetlen aszinkron metódus összes meghívása között.

A MethodNameAsyncCancel egyszinkron műveletű verziójának elnevezése azon alapul, hogy könnyebben felfedezhető a metódus egy olyan tervezési környezetben, mint a Visual Studio IntelliSense. Ez csoportosítja a kapcsolódó tagokat, és megkülönbözteti őket más tagoktól, akiknek semmi köze az aszinkron funkciókhoz. Ha arra számít, hogy további aszinkron műveletek is megjelenhetnek a következő verziókban, érdemesebb definiálni CancelAsync.

Ne definiáljon több metódust a fenti táblázatból ugyanabban az osztályban. Ez nem lesz értelme, vagy ez zsúfolt az osztály felülete a terjedése módszerek.

Ezek a metódusok általában azonnal visszatérnek, és előfordulhat, hogy a művelet ténylegesen leáll. A MethodName Completed esemény eseménykezelőjében a MethodNameCompletedEventArgs objektum tartalmaz egy Cancelled mezőt, amellyel az ügyfelek megállapíthatják, hogy a lemondás történt-e.

Tartsa be az eseményalapú aszinkron minta implementálásának ajánlott eljárásaiban leírt lemondási szemantikát.

Opcionálisan az IsBusy tulajdonság támogatása

Ha az osztály nem támogatja több egyidejű meghívást, érdemes lehet egy tulajdonságot IsBusy felfedni. Ez lehetővé teszi a fejlesztők számára annak megállapítását, hogy egy MethodNameAsync metódus fut-e anélkül, hogy kivételt észlelne a MethodNameAsync metódusból.

Tartsa be az IsBusy eseményalapú aszinkron minta implementálásának ajánlott eljárásaiban leírt szemantikát.

Opcionálisan támogatás biztosítása a folyamatjelentéshez

Gyakran kívánatos, hogy egy aszinkron művelet jelentse a művelet közbeni előrehaladást. Az eseményalapú aszinkron minta útmutatást nyújt ehhez.

  • Igény szerint definiáljon egy eseményt, amelyet az aszinkron művelet elő szeretne hívni, és meghívja a megfelelő szálon. Az ProgressChangedEventArgs objektum egy egész szám értékű folyamatjelzőt hordoz, amely várhatóan 0 és 100 között lesz.

  • Nevezze el az eseményt az alábbiak szerint:

    • ProgressChanged ha az osztály több aszinkron művelettel rendelkezik (vagy várhatóan több aszinkron műveletet fog tartalmazni a jövőbeli verziókban);

    • MethodNameProgressChanged , ha az osztály egyetlen aszinkron művelettel rendelkezik.

    Ez az elnevezési választási párhuzam a lemondási módszerhez készült, az Opcionális támogatás lemondása szakaszban leírtak szerint.

Ennek az eseménynek a meghatalmazotti aláírást ProgressChangedEventHandler és az osztályt kell használnia ProgressChangedEventArgs . Másik lehetőségként, ha megadhat egy tartományspecifikusabb állapotjelzőt (például olvasási bájtokat és teljes bájtokat egy letöltési művelethez), akkor meg kell határoznia a származtatott osztályt ProgressChangedEventArgs.

Vegye figyelembe, hogy az osztályhoz csak egy ProgressChanged vagy MethodNameProgressChanged esemény tartozik, függetlenül attól, hogy hány aszinkron metódust támogat. Az ügyfeleknek a userState MethodNameAsync metódusnak átadott objektumot kell használniuk, hogy megkülönböztessék a folyamatban lévő frissítéseket több egyidejű műveleten.

Előfordulhatnak olyan helyzetek, amikor több művelet támogatja az előrehaladást, és mindegyik egy másik mutatót ad vissza a haladáshoz. Ebben az esetben egyetlen ProgressChanged esemény nem megfelelő, és több eseményt is támogathat ProgressChanged . Ebben az esetben a MethodNameProgressChanged elnevezési mintáját használja az egyes MethodNameAsync metódusokhoz.

Tartsa be az eseményalapú aszinkron minta implementálásának ajánlott eljárásait ismertető folyamatjelentési szemantikát.

Igény szerint támogatás megadása növekményes eredmények visszaadására

Néha az aszinkron művelet a befejezés előtt növekményes eredményeket ad vissza. A forgatókönyv támogatásához számos lehetőség használható. Néhány példát követünk.

Egyműveletes osztály

Ha az osztály csak egyetlen aszinkron műveletet támogat, és ez a művelet növekményes eredményeket tud visszaadni, akkor:

  • Bővítse ki a ProgressChangedEventArgs típust a növekményes eredményadatok hordozásához, és definiáljon egy MethodNameProgressChanged eseményt ezzel a kiterjesztett adatokkal.

  • Növelje ezt a MethodNameProgressChanged eseményt , ha növekményes eredményt szeretne jelenteni.

Ez a megoldás kifejezetten egy aszinkron műveleti osztályra vonatkozik, mivel nem okoz problémát ugyanaz az esemény, amely növekményes eredményeket ad vissza az "összes műveleten", ahogyan a MethodNameProgressChanged esemény teszi.

Többműveletes osztály homogén növekményes eredményekkel

Ebben az esetben az osztály több aszinkron metódust támogat, amelyek mindegyike képes növekményes eredményeket visszaadni, és ezek a növekményes eredmények mindegyike ugyanolyan típusú adatokkal rendelkezik.

Kövesse a fent leírt modellt az egyműveletes osztályok esetében, mivel minden növekményes eredménynél ugyanaz EventArgs a struktúra működik. Adjon meg egy eseményt ProgressChanged a MethodNameProgressChanged esemény helyett, mivel több aszinkron metódusra vonatkozik.

Többműveletes osztály heterogén növekményes eredményekkel

Ha az osztály több aszinkron metódust támogat, mindegyik más típusú adatot ad vissza, a következőket kell tenni:

  • Válassza el a növekményes eredményjelentést a folyamatjelentéstől.

  • Adjon meg egy külön MethodNameProgressChanged eseményt az egyes aszinkron metódusokhoz a EventArgs metódus növekményes eredményadatainak kezeléséhez.

Hívja meg ezt az eseménykezelőt a megfelelő szálon az eseményalapú aszinkron minta implementálásának ajánlott eljárásaiban leírtak szerint.

Out and Ref Parameters in Methods (Out and Ref Parameters in Methods) kezelése

Bár a .NET használata out és ref használata általában elriasztja őket, a következő szabályokat kell követni, amikor jelen vannak:

A MethodName szinkron metódust használva:

  • outA MethodName paraméterei nem lehetnek a MethodNameAsync részei. Ehelyett a MethodNameCompletedEventArgs elemnek kell lenniük, amelynek neve megegyezik a MethodName paraméterével (hacsak nincs megfelelőbb név).

  • refA MethodName paramétereinek a MethodNameAsync részeként, valamint a MethodName CompletedEventArgs metódusnév részeként kell megjelennie, amelynek a paramétere megegyezik a MethodName paraméterével (hacsak nincs megfelelőbb név).

Például:

Public Function MethodName(ByVal arg1 As String, ByRef arg2 As String, ByRef arg3 As String) As Integer
public int MethodName(string arg1, ref string arg2, out string arg3);

Az aszinkron metódus és osztálya AsyncCompletedEventArgs a következőképpen nézne ki:

Public Sub MethodNameAsync(ByVal arg1 As String, ByVal arg2 As String)

Public Class MethodNameCompletedEventArgs
    Inherits System.ComponentModel.AsyncCompletedEventArgs
    Public ReadOnly Property Result() As Integer
    End Property
    Public ReadOnly Property Arg2() As String
    End Property
    Public ReadOnly Property Arg3() As String
    End Property
End Class
public void MethodNameAsync(string arg1, string arg2);

public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
{
    public int Result { get; };
    public string Arg2 { get; };
    public string Arg3 { get; };
}

Lásd még