As Stephen said, the easiest way to ensure thread safety in this case is to use indispensable event arguments.
In most cases, even the arguments are used only to notify observers without any requirements for changes from the observed side to the observer (i.e., from the subscriber to the event owner). In some special cases, such as implementing an event chain, the arguments to the template design pattern should be mutable, but in all other cases they should not.
The inevitability in this case will help you not only easily implement compatible handlers, but also lead to a clearer design and improve maintainability, since now you have the opportunity to misuse your API.
Conclusion : you must implement your thread safety methods, but you should be aware that an unhandled exception from the event handler will be swallowed if your event is fired from a thread other than the UI.
There is a danger of using async void methods: if this method fails and you call it in an environment without a synchronization context (for example, from a thread pool thread from a console application), you will get an unhandled domain exception that the application closes:
internal class Program { static Task Boo() { return Task.Run(() => { throw new Exception("111"); }); } private static async void Foo() { await Boo(); } static void Main(string[] args) {
source share