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.
V předchozím článku jsme se zabývali nejběžnějšími vzory událostí. .NET Core má uvolněnější vzor. V této verzi již definice EventHandler<TEventArgs> nemá omezení, že TEventArgs musí být třída odvozená z System.EventArgs.
To zvyšuje flexibilitu pro vás a je zpětně kompatibilní. Začněme flexibilitou. Implementace pro System.EventArgs používá metodu definovanou v System.Object jedné metodě: MemberwiseClone(), která vytváří mělkou kopii objektu. Tato metoda musí používat reflexi, aby bylo možné implementovat její funkce pro všechny třídy odvozené z EventArgs. Tato funkce je jednodušší vytvořit v konkrétní odvozené třídě. To znamená, že odvození z System.EventArgs je omezení, které omezuje vaše návrhy, ale neposkytuje žádné další výhody. Ve skutečnosti můžete změnit definice FileFoundArgs a SearchDirectoryArgs tak, aby se neodvozují z EventArgs. Program funguje úplně stejně.
Můžete také změnit SearchDirectoryArgs na strukturu, pokud provedete jednu další změnu:
internal struct SearchDirectoryArgs
{
internal string CurrentSearchDirectory { get; }
internal int TotalDirs { get; }
internal int CompletedDirs { get; }
internal SearchDirectoryArgs(string dir, int totalDirs, int completedDirs) : this()
{
CurrentSearchDirectory = dir;
TotalDirs = totalDirs;
CompletedDirs = completedDirs;
}
}
Další změnou je volání konstruktoru bez parametrů před zadáním konstruktoru, který inicializuje všechna pole. Bez tohoto doplňku by pravidla jazyka C# hlásila, že se k vlastnostem přistupuje, než jsou přiřazeny.
Neměli byste měnit FileFoundArgs z třídy (typ odkazu) na strukturu (typ hodnoty). Protokol pro zpracování zrušení vyžaduje předání argumentů události odkazem. Pokud jste provedli stejnou změnu, třída vyhledávání souborů nemohla nikdy sledovat žádné změny provedené žádným odběratelem události. Pro každého odběratele by se použila nová kopie struktury a tato kopie by byla jiná než kopie zobrazená objektem vyhledávání souborů.
Teď se podíváme na to, jak může být tato změna zpětně kompatibilní. Odebrání omezení nemá vliv na žádný existující kód. Všechny existující typy argumentů událostí se stále odvozují z System.EventArgs. Zpětná kompatibilita je jedním z hlavních důvodů, proč se nadále odvozují z System.EventArgs. Předplatitelé všech existujících událostí jsou odběrateli události, která dodržovala klasický vzor.
Po podobné logice by žádný typ argumentu události vytvořený nyní neměl žádné odběratele v žádném existujícím základu kódu. Nové typy událostí, které nejsou odvozeny z System.EventArgs tyto základy kódu neporuší.
Události s odběrateli Async
Máte se naučit poslední vzor: Jak správně psát odběratele událostí, kteří volají asynchronní kód. Výzva je popsaná v článku o async a await. Asynchronní metody můžou mít návratový typ void, ale to se nedoporučuje. Když kód odběratele události volá asynchronní metodu, nezbývá vám, než vytvořit metodu async void. Podpis pro obslužnou rutinu události to vyžaduje.
Musíte srovnat tyto protichůdné pokyny. Nějakým způsobem musíte vytvořit bezpečnou metodu async void. Základy modelu, který potřebujete implementovat, se zobrazují v následujícím kódu:
worker.StartWorking += async (sender, eventArgs) =>
{
try
{
await DoWorkAsync();
}
catch (Exception e)
{
//Some form of logging.
Console.WriteLine($"Async task failure: {e.ToString()}");
// Consider gracefully, and quickly exiting.
}
};
Nejprve si všimněte, že obslužná rutina je označená jako asynchronní. Vzhledem k tomu, že je přiřazen typu delegáta pro obsluhu události, jeho návratový typ je void. To znamená, že musíte postupovat podle vzoru zobrazeného v obslužné rutině a nepovolit vyvolání výjimek z kontextu asynchronní obslužné rutiny. Protože nevrací úkol, neexistuje žádný úkol, který by mohl ohlásit chybu zadáním chybného stavu. Vzhledem k tomu, že metoda je asynchronní, metoda nemůže vyvolat výjimku. (Volající metoda pokračuje v provádění, protože je async.) Skutečné chování modulu runtime je definováno odlišně pro různá prostředí. Může ukončit vlákno nebo proces, který vlastní vlákno, nebo ponechat proces v nedeterminátu stavu. Všechny tyto potenciální výsledky jsou vysoce nežádoucí.
Výraz await pro asynchronní úlohu byste měli zabalit do vlastního bloku try. Pokud to způsobí chybnou úlohu, můžete chybu protokolovat. Pokud se jedná o chybu, ze které se vaše aplikace nemůže obnovit, můžete program rychle a elegantně ukončit.
Tento článek vysvětluje hlavní aktualizace vzoru událostí .NET. V knihovnách, se kterými pracujete, se může zobrazit mnoho příkladů předchozích verzí. Měli byste ale také rozumět tomu, jaké jsou nejnovější trendy. Dokončený kód ukázky můžete zobrazit na Program.cs.
Další článek v této sérii vám pomůže rozlišovat mezi používáním delegates a events ve vašich návrzích. Jsou to podobné koncepty a tento článek vám pomůže učinit nejlepší rozhodnutí pro vaše programy.