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


Ajánlott eljárások az eseményalapú aszinkron minta implementálására

Az eseményalapú aszinkron minta hatékonyan teszi elérhetővé az aszinkron viselkedést az osztályokban, jól ismert eseményekkel és delegált szemantikával. Az eseményalapú aszinkron minta implementálásához bizonyos viselkedési követelményeket kell követnie. A következő szakaszok az eseményalapú aszinkron mintát követő osztály megvalósításakor figyelembe veendő követelményeket és irányelveket ismertetik.

Áttekintésért lásd az eseményalapú aszinkron minta implementálását.

Szükséges viselkedési garanciák

Ha implementálja az eseményalapú aszinkron mintát, számos garanciát kell biztosítania annak biztosítására, hogy az osztály megfelelően viselkedjen, és az osztály ügyfelei támaszkodhatnak erre a viselkedésre.

Befejezése

Mindig hívja meg a MethodNameCompleted eseménykezelőt sikeres befejezés, hiba vagy lemondás esetén. Az alkalmazásoknak soha nem szabad olyan helyzetbe ütközniük, amikor tétlenek maradnak, és a befejezés soha nem történik meg. A szabály alól kivételt képez az, ha maga az aszinkron művelet úgy van kialakítva, hogy soha ne fejeződjön be.

Befejezett esemény és EventArgs

Minden különálló MethodNameAsync metódus esetében alkalmazza a következő tervezési követelményeket:

  • Adjon meg egy MethodNameCompleted eseményt ugyanazon az osztályon, mint a metódus.

  • Definiáljon egy osztályt EventArgs és a hozzá tartozó meghatalmazottat az osztályból AsyncCompletedEventArgs származó MethodNameCompleted eseményhez. Az alapértelmezett osztálynévnek a MethodNameCompletedEventArgs űrlapnak kell lennie.

  • Győződjön meg arról, hogy az EventArgs osztály a MethodName metódus visszatérési értékeire jellemző. Amikor az osztályt EventArgs használja, soha ne követelje meg a fejlesztőktől, hogy leadják az eredményt.

    Az alábbi példakód a tervezési követelmény jó és rossz implementációját mutatja be.

// Good design
private void Form1_MethodNameCompleted(object sender, xxxCompletedEventArgs e)
{
    DemoType result = e.Result;
}

// Bad design
private void Form1_MethodNameCompleted(object sender, MethodNameCompletedEventArgs e)
{
    DemoType result = (DemoType)(e.Result);
}
  • Ne adjon meg osztályt EventArgs a visszaadott voidmetódusokhoz. Ehelyett használja az osztály egy példányát AsyncCompletedEventArgs .

  • Győződjön meg arról, hogy mindig a MethodNameCompleted eseményt emeli ki. Ezt az eseményt sikeres befejezés, hiba vagy lemondás esetén kell előhozni. Az alkalmazásoknak soha nem szabad olyan helyzetbe ütközniük, amikor tétlenek maradnak, és a befejezés soha nem történik meg.

  • Győződjön meg arról, hogy az aszinkron művelet során előforduló kivételeket észleli, és hozzárendeli a kifogott kivételt a Error tulajdonsághoz.

  • Ha hiba történt a feladat végrehajtása során, az eredmények nem lesznek elérhetők. Ha a Error tulajdonság nem null, győződjön meg arról, hogy a struktúra bármely tulajdonságának EventArgs elérése kivételt jelent. Az ellenőrzés végrehajtásához használja a RaiseExceptionIfNecessary metódust.

  • Az időtúllépést hibaként modellezheti. Időtúllépés esetén emelje fel a MethodNameCompleted eseményt, és rendeljen hozzá egy TimeoutException tulajdonságot Error .

  • Ha az osztály több egyidejű meghívást is támogat, győződjön meg arról, hogy a MethodNameCompleted esemény tartalmazza a megfelelő userSuppliedState objektumot.

  • Győződjön meg arról, hogy a MethodNameCompleted esemény a megfelelő szálon és az alkalmazás életciklusának megfelelő időpontban van előállítva. További információ: Szálkezelés és környezetek szakasz.

Műveletek egyidejű végrehajtása

  • Ha az osztály több egyidejű meghívást is támogat, engedélyezze a fejlesztőnek az egyes meghívások külön-külön történő nyomon követését a MethodNameAsync túlterhelés meghatározásával, amely egy objektumértékkel rendelkező állapotparamétert vagy nevű userSuppliedStatefeladatazonosítót vesz igénybe. Ennek a paraméternek mindig az utolsó paraméternek kell lennie a MethodNameAsync metódus aláírásában.

  • Ha az osztály az objektumértékelt állapotparamétert vagy tevékenységazonosítót használó MethodNameAsync túlterhelést definiálja, mindenképpen kövesse nyomon a művelet élettartamát ezzel a tevékenységazonosítóval, és mindenképpen adja vissza a befejezési kezelőnek. Vannak segítő osztályok, amelyek segítséget nyújtanak. Az egyidejűség kezelésével kapcsolatos további információkért lásd : Az eseményalapú aszinkron mintát támogató összetevő implementálása.

  • Ha az osztály az állapotparaméter nélkül határozza meg a MethodNameAsync metódust, és nem támogatja több egyidejű meghívást, győződjön meg arról, hogy a MethodNameAsync meghívásának korábbi MethodNameAsync-meghívása előtt végrehajtott kísérlete egy .InvalidOperationException

  • Általában ne tegyen kivételt, ha a paraméter nélküli userSuppliedState MethodNameAsync metódust többször is meghívja a rendszer, hogy több függőben lévő művelet legyen. Kivételt jelenthet, ha az osztály kifejezetten nem tudja kezelni ezt a helyzetet, de tegyük fel, hogy a fejlesztők képesek kezelni ezeket a többszörös megkülönböztethetetlen visszahívásokat

Eredmények elérése

Állapotjelentés

  • Ha lehetséges, támogassa a folyamatjelentést. Ez lehetővé teszi a fejlesztők számára, hogy jobb felhasználói élményt nyújtsanak az alkalmazásnak az osztály használata során.

  • Ha ProgressChanged vagy MethodNameProgressChanged eseményt implementál, győződjön meg arról, hogy a művelet MethodNameCompleted eseményének létrehozása után nem történik ilyen esemény egy adott aszinkron művelethez.

  • Ha a szabvány feltöltése folyamatban van, győződjön meg arról, hogy a ProgressPercentage szabvány ProgressChangedEventArgs mindig százalékos értékként értelmezhető. A százaléknak nem kell pontosnak lennie, de százalékos értéket kell képviselnie. Ha az állapotjelentési metrikának nem százalékos értéknek kell lennie, származtass egy osztályt az ProgressChangedEventArgs osztályból, és hagyd ProgressPercentage 0-nál. Kerülje a százaléktól eltérő jelentési metrikák használatát.

  • Győződjön meg arról, hogy az ProgressChanged esemény a megfelelő szálon és az alkalmazás életciklusának megfelelő időpontban történik. További információ: Szálkezelés és környezetek szakasz.

IsBusy implementáció

  • Ne tegye közzé a tulajdonságot IsBusy , ha az osztály több egyidejű meghívást is támogat. Az XML-webszolgáltatás proxyi például nem tesznek közzé tulajdonságot IsBusy , mert az aszinkron metódusok több egyidejű meghívását támogatják.

  • A tulajdonságnak a MethodNameAsync metódus meghívása után és a MethodNameCompleted esemény létrehozása előtt kell visszatérnietrue.IsBusy Ellenkező esetben vissza kell térnie false. WebClient Az BackgroundWorker és az összetevők olyan osztályokra mutatnak be példákat, amelyek egy tulajdonságot IsBusy fednek fel.

Érvénytelenítés

  • Ha lehetséges, támogassa a lemondást. Ez lehetővé teszi a fejlesztők számára, hogy jobb felhasználói élményt nyújtsanak az alkalmazásnak az osztály használata során.

  • Lemondás esetén állítsa be a jelölőt Cancelled az AsyncCompletedEventArgs objektumba.

  • Győződjön meg arról, hogy az eredmény elérésére tett kísérletek azt jelzik InvalidOperationException , hogy a műveletet megszakították. Az ellenőrzés végrehajtásához használja a AsyncCompletedEventArgs.RaiseExceptionIfNecessary metódust.

  • Győződjön meg arról, hogy a lemondási metódusra irányuló hívások mindig sikeresen visszatérnek, és soha nem emelnek kivételt. Általánosságban elmondható, hogy az ügyfél nem kap értesítést arról, hogy egy művelet valóban bármikor visszavonható-e, és nem kap értesítést arról, hogy a korábban kiadott lemondás sikeres volt-e. Az alkalmazás azonban mindig értesítést kap, ha a lemondás sikeres volt, mivel az alkalmazás részt vesz a befejezési állapotban.

  • A művelet megszakítása esetén emelje ki a MethodNameCompleted eseményt.

Hibák és kivételek

  • Az aszinkron műveletben előforduló kivételeket észlelve állítsa a tulajdonság értékét erre a AsyncCompletedEventArgs.Error kivételre.

Szálkezelés és környezetek

Az osztály megfelelő működéséhez kritikus fontosságú, hogy az ügyfél eseménykezelői az adott alkalmazásmodell megfelelő szálán vagy környezetében legyenek meghívva, beleértve a ASP.NET és a Windows Forms-alkalmazásokat is. Két fontos segédosztály biztosítja, hogy az aszinkron osztály megfelelően viselkedjen bármely alkalmazásmodellben: AsyncOperation és AsyncOperationManager.

AsyncOperationManager egy metódust ad vissza, CreateOperationamely egy AsyncOperation. A MethodNameAsync metódushívások CreateOperation és az osztály a visszaadott AsyncOperation érték használatával követi nyomon az aszinkron feladat élettartamát.

Az előrehaladás, a növekményes eredmények és a befejezés ügyfélnek való jelentéséhez hívja meg a PostOperationCompletedAsyncOperation. AsyncOperation felelős az ügyfél eseménykezelőinek a megfelelő szálra vagy környezetre irányuló hívások rendezéséért.

Feljegyzés

Ezeket a szabályokat megkerülheti, ha kifejezetten az alkalmazásmodell házirendjéhez szeretne igazodni, de továbbra is élvezheti az eseményalapú aszinkron minta használatának egyéb előnyeit. Előfordulhat például, hogy egy Windows Formsban működő osztályt szeretne szabadon csoportosítani. Létrehozhat egy ingyenes szálas osztályt, amíg a fejlesztők megértik a hallgatólagos korlátozásokat. A konzolalkalmazások nem szinkronizálják a hívások végrehajtását Post . Ez miatt ProgressChanged az események sorrenden kívülre kerülnek. Ha a hívások szerializált végrehajtását Post szeretné végrehajtani, implementáljon és telepítsen egy osztályt System.Threading.SynchronizationContext .

Az aszinkron műveletek használatával AsyncOperation és AsyncOperationManager engedélyezésével kapcsolatos további információkért lásd : Az eseményalapú aszinkron mintát támogató összetevő implementálása.

Irányelvek

  • Ideális esetben minden metódushívásnak függetlennek kell lennie másoktól. Kerülje a meghívások megosztott erőforrásokkal való összekapcsolását. Ha az erőforrásokat meg kell osztani a meghívások között, megfelelő szinkronizálási mechanizmust kell biztosítania a megvalósításban.

  • Azokat a terveket, amelyek megkövetelik az ügyféltől a szinkronizálás implementálását, elriasztják. Létrehozhat például egy aszinkron metódust, amely paraméterként globális statikus objektumot fogad; egy ilyen metódus több egyidejű meghívása adatsérülést vagy holtpontot eredményezhet.

  • Ha olyan metódust implementál, amely túlterheli a többszörös meghívást (userState az aláírásban), az osztálynak kezelnie kell a felhasználói állapotok vagy feladatazonosítók gyűjteményét, valamint a hozzájuk tartozó függőben lévő műveleteket. Ezt a gyűjteményt régiókkal lock kell védeni, mert a különböző meghívások objektumokat adnak hozzá és távolítanak el userState a gyűjteményben.

  • Fontolja meg az osztályok újrafelhasználását CompletedEventArgs , ahol lehetséges és megfelelő. Ebben az esetben az elnevezés nem egyezik a metódus nevével, mert egy adott delegált és EventArgs típus nem egyetlen metódushoz van kötve. A fejlesztőket azonban arra kényszeríti, hogy a tulajdonságból EventArgs lekért értéket soha nem fogadják el.

  • Ha olyan osztályt hoz létre, amelyből Componentszármazik, ne implementálja és telepítse saját osztályát SynchronizationContext . Az alkalmazásmodellek, nem az összetevők vezérlik a SynchronizationContext használt elemeket.

  • Ha bármilyen típusú többszálú elemet használ, előfordulhat, hogy nagyon komoly és összetett hibáknak teszi ki magát. A többszálas megoldás implementálása előtt tekintse meg a felügyelt szálkezelés ajánlott eljárásait.

Lásd még