2

In regards to

Application.Current.Dispatcher.Invoke(action);

I have looked at CheckAccess() and various ways of determining whether i'm on the main UI thread. Though after looking at the Dispatcher Source code for Invoke, it seems to call CheckAccess() and performs other checks anyway

Invoke Source Code

public void Invoke(Action callback, DispatcherPriority priority, CancellationToken cancellationToken, TimeSpan timeout)
{
   ...
   ...

   // Fast-Path: if on the same thread, and invoking at Send priority,
   // and the cancellation token is not already canceled, then just
   // call the callback directly.
   if (!cancellationToken.IsCancellationRequested && priority == DispatcherPriority.Send && CheckAccess())
   {
      SynchronizationContext oldSynchronizationContext = SynchronizationContext.Current;

      try
      {
         DispatcherSynchronizationContext newSynchronizationContext;
         if (BaseCompatibilityPreferences.GetReuseDispatcherSynchronizationContextInstance())
         {
            newSynchronizationContext = _defaultDispatcherSynchronizationContext;
         }
         else
         {
            if (BaseCompatibilityPreferences.GetFlowDispatcherSynchronizationContextPriority())
            {
               newSynchronizationContext = new DispatcherSynchronizationContext(this, priority);
            }
            else
            {
               newSynchronizationContext = new DispatcherSynchronizationContext(this, DispatcherPriority.Normal);
            }
         }
         SynchronizationContext.SetSynchronizationContext(newSynchronizationContext);

         callback();
         ...

So the most reliable way to check whether my dialog needs to be invoked is by calling Invoke? looking at CheckAccess and SynchronisationContexts solutions when i dont have access to a Control seem to be redundant.

Is this the case or is there some edge cases i'm missing, or hidden performance hit i cant see?

TheGeneral
  • 79,002
  • 9
  • 103
  • 141

1 Answers1

3

I guess it depends.

If you're mainly after correctness and/or code brevity, then yes, the call is redundant - calling

Dispatcher.Invoke(action);

will be functionally equivalent1 to

if(Dispatcher.CheckAccess())
    action();
else
    Dispatcher.Invoke(action);

If however your concern is performance, then it's not so obvious. CheckAccess literally reads

return Thread == Thread.CurrentThread;

so even if it's called twice as many times, it will hardly be noticeable. Dispatcher.Invoke however does some additional work, such as argument checking and, possibly, swapping synchronization context, so I guess it potentially has larger overhead than a redundant call to CheckAccess(). But, as usual with performance optimization, there's no single right answer - it depends on your particular case (for example on the likelihood of this code being called from non-UI thread).


1 Obviously there may be additional things happening with the synchronization context when calling Dispatcher.Invoke, but unless action is making use of it, the result will be the same

Grx70
  • 10,041
  • 1
  • 40
  • 55
  • The particular use case is that its just unknown if the thread is UI, long story short its basically a global error handler for a last ditch effort to alert the user through a dialog. however thanks for the detailed response – TheGeneral Jan 23 '18 at 07:52