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óért a BackgroundWorker-ról lásd: Hogyan kell: 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

  • Az out és ref paraméterek kezelése metódusokban

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 és IAsyncResult objektumokra aszinkron műveletekhez, ami azt jelenti, hogy az ügyfélnek kell kialakítania a lekérdezést, és létrehoznia WaitAll vagy WaitAny.

  • 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:

  • Visszatér void.

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

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

Igény szerint definiálhat egy `MethodNameAsync` túlterhelést, amely azonos `MethodNameAsync`-szal, de kiegészül egy további objektumértékkel rendelkező paraméterrel. 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 egy példányt AsyncCompletedEventArgs önmagában.

      Megjegyzés:

      A delegáltak és AsyncCompletedEventArgs típusok újrafelhasználása – ha lehetséges és megfelelő – tökéletesen elfogadható. Ebben az esetben az elnevezés nem lesz olyan következetes a függvény nevével, mivel egy adott delegált és AsyncCompletedEventArgs nem lesz egyetlen függvényhez 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 elfogad egy userState paramétert, és lehetővé teszi a többszöri meghívást, mielőtt várna bármelyik befejezésére?

Az alábbi táblázatban szereplő két kérdésre adott válaszok segítségével meghatározhatja, hogy milyen legyen a visszavonási módszer szignálási módja.

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. Ennek így nincs értelme, vagy zsúfolttá teszi az osztály felületét a módszerek elburjánzása.

Ezek a metódusok általában azonnal visszatérnek, és előfordulhat, hogy a művelet ténylegesen leáll. A MethodNameCompleted 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 IsBusy tulajdonságot elérhetővé tenni. 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 IsBusyesemé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 döntés párhuzamos a lemondási módszerrel, ahogyan azt az „Opcionálisan támogassa a lemondást” szakasz leírja.

Ennek az eseménynek a ProgressChangedEventHandler delegált aláírást és a ProgressChangedEventArgs osztályt kell használnia. 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 userStateMethodNameAsync 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 megfontolhatja több ProgressChanged esemény támogatását. 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 ProgressChanged eseményt a MethodNameProgressChanged esemény helyett, mivel több aszinkron metódusra is 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.

  • Definiáljon külön MethodNameProgressChanged eseményt az egyes aszinkron metódusok számára, a megfelelő EventArgs használatával a 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.

Az out és ref paraméterek kezelése metódusokban

Bár a out és ref használata általában nem ajánlott a .NET-ben, vannak szabályok, amelyeket követni kell, amikor jelen vannak.

A MethodName szinkron metódust használva:

  • out A 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).

  • ref A MethodName paramétereinek a MethodNameAsync részeként, valamint a MethodNameCompletedEventArgs 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