Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Asynchronní vzor založený na událostech poskytuje efektivní způsob zpřístupnění asynchronního chování ve třídách se známou sémantikou událostí a delegátů. Pokud chcete implementovat asynchronní vzor založený na událostech, musíte postupovat podle určitých požadavků na chování. Následující části popisují požadavky a pokyny, které byste měli zvážit při implementaci třídy, která se řídí asynchronním vzorem založeným na událostech.
Přehled najdete v tématu Implementace asynchronního vzoru založeného na událostech.
Požadované záruky chování
Pokud implementujete asynchronní vzor založený na událostech, musíte poskytnout řadu záruk, abyste zajistili, že se vaše třída bude chovat správně a klienti vaší třídy mohou spoléhat na takové chování.
Dokončení
Vždy vyvolejte obslužnou rutinu události MethodNameCompleted pokud máte úspěšné dokončení, chybu nebo zrušení. Aplikace by nikdy neměly narazit na situaci, kdy zůstanou nečinné a k dokončení nikdy nedojde. Jednou z výjimek tohoto pravidla je, pokud je samotná asynchronní operace navržena tak, aby se nikdy nedokončí.
Dokončená událost a eventArgs
Pro každou samostatnou metodu MethodNameAsync použijte následující požadavky na návrh:
Definujte událost MethodNameCompleted ve stejné třídě jako metoda.
Definujte třídu a doprovodného EventArgs delegáta pro událost MethodNameCompleted , která je odvozena od AsyncCompletedEventArgs třídy. Výchozí název třídy by měl být form MethodNameCompletedEventArgs.
Ujistěte se, že EventArgs je třída specifická pro vrácené hodnoty MethodName metody. Při použití třídy EventArgs byste nikdy neměli požadovat, aby vývojáři přetypovávali výsledek.
Následující příklad kódu ukazuje dobrou a špatnou implementaci tohoto požadavku na návrh v uvedeném pořadí.
// 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);
}
Nedefinujte EventArgs třídu pro vrácení metod, které vracejí
void. Místo toho použijte instanci AsyncCompletedEventArgs třídy.Ujistěte se, že vždy vyvoláte událost MethodNameCompleted . Tato událost by měla být vyvolána při úspěšném dokončení, při chybě nebo při zrušení. Aplikace by nikdy neměly narazit na situaci, kdy zůstanou nečinné a k dokončení nikdy nedojde.
Zachyťte všechny výjimky, ke kterým dochází v asynchronní operaci, a přiřaďte zachycenou výjimku vlastnosti Error .
Pokud při dokončení úkolu došlo k chybě, výsledky by neměly být přístupné. Error Pokud vlastnost není
null, ujistěte se, že přístup k jakékoli vlastnosti ve EventArgs struktuře vyvolá výjimku. K provedení tohoto ověření použijte metodu RaiseExceptionIfNecessary .Modeluj časový limit jako chybu. Pokud dojde k vypršení časového limitu, vytvořte událost MethodNameCompleted a přiřaďte TimeoutException k Error vlastnosti.
Pokud vaše třída podporuje více souběžných vyvolání, ujistěte se, že methodNameCompleted událost obsahuje příslušný
userSuppliedStateobjekt.Ujistěte se, že je událost MethodNameCompleted vyvolána v příslušném vlákně a v příslušné době v životním cyklu aplikace. Další informace najdete v části Vlákna a Kontexty.
Souběžné provádění operací
Pokud vaše třída podporuje více souběžných vyvolání, umožněte vývojáři sledovat každé vyvolání samostatně definováním přetížení metody MethodNameAsync, které přijímá parametr stavu s hodnotou objektu nebo ID úlohy ve formě
userSuppliedState. Tento parametr by měl být vždy posledním parametrem v podpisu metody MethodNameAsync .Pokud vaše třída definuje přetížení MethodNameAsync, které přijímá parametr stavu s hodnotou objektu nebo ID úkolu, nezapomeňte sledovat životnost operace s tímto ID úkolu a nezapomeňte jej vrátit zpět do obslužné rutiny dokončení. K dispozici jsou pomocné třídy, které vám pomůžou. Další informace o správě souběžnosti najdete v tématu Postupy: Implementace komponenty, která podporuje asynchronní vzor založený na událostech.
Pokud vaše třída definuje metodu MethodNameAsync bez parametru stavu a nepodporuje více souběžných vyvolání, ujistěte se, že jakýkoli pokus o vyvolání MethodNameAsync před dokončením předchozího volání MethodNameAsync vyvolá InvalidOperationException.
Obecně platí, že nevyvolávejte výjimku, pokud metoda MethodNameAsync bez parametru
userSuppliedStateje vyvolána vícekrát, takže existuje více nevyřízených operací. Výjimku můžete vyvolat, když vaše třída explicitně nemůže tuto situaci zpracovat, ale předpokládá se, že vývojáři mohou zpracovávat tato mnohá nerozlišitelná zpětná volání.
Přístup k výsledkům
Pokud během provádění asynchronní operace došlo k chybě, výsledky by neměly být přístupné. Ujistěte se, že přístup k jakékoli vlastnosti v AsyncCompletedEventArgs v případě, že Error není
null, vyvolá výjimku odkazovanou Error. Třída AsyncCompletedEventArgs poskytuje metodu RaiseExceptionIfNecessary pro tento účel.Zajistěte, aby všechny pokusy o přístup k výsledku vyvolaly InvalidOperationException oznámení, že operace byla zrušena. K provedení tohoto ověření použijte metodu AsyncCompletedEventArgs.RaiseExceptionIfNecessary .
Generování zpráv o průběhu
Pokud je to možné, podporují vykazování průběhu. Vývojáři tak můžou poskytovat lepší uživatelské prostředí aplikací, když používají vaši třídu.
Pokud implementujete událost ProgressChanged nebo MethodNameProgressChanged, ujistěte se, že pro konkrétní asynchronní operaci nejsou vyvolány žádné takové události po vyvolání události MethodNameCompleted.
Pokud se vyplňuje standard ProgressChangedEventArgs, ujistěte se, že ProgressPercentage lze vždy interpretovat jako procento. Procento nemusí být přesné, ale mělo by představovat procento. Pokud vaše metrika hlášení o pokroku musí být něčím jiným než procenty, odvoďte třídu z třídy ProgressChangedEventArgs a ponechte ProgressPercentage na 0. Nepoužívejte žádnou jinou metriku než procentuální hodnotu.
Ujistěte se, že
ProgressChangedje událost vyvolána v příslušném vlákně a v příslušném čase v životním cyklu aplikace. Další informace najdete v části Vlákna a Kontexty.
Implementace IsBusy
Nevystavujte
IsBusyvlastnost, pokud vaše třída podporuje více souběžných vyvolání. Například proxy webové služby XML nezpřístupňujíIsBusyvlastnost, protože podporují více souběžných vyvolání asynchronních metod.Vlastnost
IsBusyby se měla vrátittruepo zavolání metody MethodNameAsync a před vyvolání události MethodNameCompleted . V opačném případě by se měl vrátitfalse. Komponenty BackgroundWorker a WebClient jsou příklady tříd, které zpřístupňují vlastnostIsBusy.
Zrušení
Podpořte zrušení, pokud je to možné. Vývojáři tak můžou poskytovat lepší uživatelské prostředí aplikací, když používají vaši třídu.
V případě zrušení nastavte v objektu Cancelled příznak AsyncCompletedEventArgs.
Zajistěte, aby všechny pokusy o přístup k výsledku vyvolaly InvalidOperationException oznámení, že operace byla zrušena. K provedení tohoto ověření použijte metodu AsyncCompletedEventArgs.RaiseExceptionIfNecessary .
Ujistěte se, že volání metody pro zrušení vždy úspěšně skončí a nikdy nevyvolá výjimku. Obecně platí, že klient není upozorněn na to, zda je operace v daném okamžiku skutečně zrušená, a není upozorněna na to, zda bylo dříve vydané zrušení úspěšné. Aplikaci však bude vždy doručeno oznámení, pokud se zrušení podaří, protože aplikace se podílí na stavu dokončení.
Vyvolání události MethodNameCompleted při zrušení operace.
Chyby a výjimky
- Zachyťte všechny výjimky, ke kterým dochází v asynchronní operaci, a nastavte hodnotu AsyncCompletedEventArgs.Error vlastnosti na danou výjimku.
Vlákna a kontexty
Pro správnou operaci třídy je důležité, aby obslužné rutiny událostí klienta byly vyvolány ve správném vlákně nebo kontextu pro daný aplikační model, včetně ASP.NET a aplikací Modelu Windows Forms. K zajištění správného chování asynchronní třídy v libovolném aplikačním modelu jsou k dispozici dvě důležité pomocné třídy: AsyncOperation a AsyncOperationManager.
AsyncOperationManager poskytuje jednu metodu, CreateOperation která vrací AsyncOperation. Vaše metoda MethodNameAsync volá CreateOperation a vaše třída používá vrácenou AsyncOperation ke sledování životnosti asynchronní úlohy.
Chcete-li hlásit průběh, přírůstkové výsledky a dokončení klientovi, zavolejte metodu Post a metodu OperationCompleted na objektu AsyncOperation. AsyncOperation zodpovídá za zařazování volání obslužných rutin událostí klienta do správného vlákna nebo kontextu.
Poznámka:
Tato pravidla můžete obejít, pokud chcete explicitně přejít proti zásadám aplikačního modelu, ale přesto můžete využít další výhody použití asynchronního vzoru založeného na událostech. Můžete například chtít, aby třída, která pracuje ve Windows Forms, byla bez vláken. Můžete vytvořit bezplatnou třídu s vlákny, pokud vývojáři chápou implicitní omezení. Konzolové aplikace nesynchronizují provádění Post volání. To může způsobit ProgressChanged vyvolání událostí mimo pořadí. Pokud chcete mít serializované provádění Post volání, implementujte a nainstalujte System.Threading.SynchronizationContext třídu.
Další informace o použití AsyncOperation a AsyncOperationManager povolení asynchronních operací naleznete v tématu Postupy: Implementace komponenty, která podporuje asynchronní vzor založený na událostech.
Pokyny
V ideálním případě by každé vyvolání metody mělo být nezávislé na ostatních. Měli byste se vyhnout spojování volání se sdílenými prostředky. Pokud se prostředky mají sdílet mezi vyvoláním, budete muset ve své implementaci poskytnout správný synchronizační mechanismus.
Návrhy, které vyžadují, aby klient implementoval synchronizaci, se nedoporučuje. Můžete mít například asynchronní metodu, která přijímá globální statický objekt jako parametr; více souběžných vyvolání takové metody může vést k poškození dat nebo zablokování.
Pokud implementujete metodu s přetížením vícenásobného vyvolání (
userStatev podpisu), vaše třída bude muset spravovat kolekci stavů uživatelů nebo ID úkolů a jejich odpovídající čekající operace. Tato kolekce by měla být chráněna oblastmilock, protože různé operace přidávají a odebírajíuserStateobjekty v kolekci.Zvažte opětovné použití
CompletedEventArgstříd, pokud je to možné a vhodné. V tomto případě není pojmenování konzistentní s názvem metody, protože daný delegát a EventArgs typ nejsou svázané s jedinou metodou. Nutit vývojáře k přetypování hodnoty načtené z vlastnosti na objektu EventArgs není nikdy přijatelné.Pokud vytváříte třídu odvozenou z Component, neimplementujte a nainstalujte vlastní SynchronizationContext třídu. Modely aplikací, nikoli komponenty, řídí SynchronizationContext, které se používají.
Pokud používáte multithreading jakéhokoli druhu, můžete se potenciálně vystavit velmi vážným a složitým chybám. Před implementací jakéhokoli řešení, které používá vícevláknové zpracování, si přečtěte osvědčené postupy pro spravované vlákno.
Viz také
- AsyncOperation
- AsyncOperationManager
- AsyncCompletedEventArgs
- ProgressChangedEventArgs
- BackgroundWorker
- Implementace asynchronního vzoru založeného na událostech
- Asynchronní vzor založený na událostech (EAP)
- Rozhodování o implementaci asynchronního vzoru založeného na událostech
- Osvědčené postupy pro implementaci asynchronního vzoru založeného na událostech
- Postupy: Použití komponent, které podporují asynchronní vzor založený na událostech
- Postupy: Implementace komponenty, která podporuje asynchronní vzor založený na událostech