The shortest and most correct way to avoid cross-flow errors?

I do not treat delegates very well, and I do not understand what is happening under the hood. I get a cross thread operation error when accessing user interface elements from another thread.

What I want to do is write a generic function in the Utility class so that I can pass any method / code block to a function. I can do this in many ways:

  •  delegate void UpdateGui(Control c, Action action); public static void Do(Control c, Action action) { try { if (c.InvokeRequired) { UpdateGui updaterdelegate = new UpdateGui(Do); c.TopLevelControl.Invoke(updaterdelegate, new object[] { c, action }); } else action(); } catch (Exception ex) { //throw ex; } } 
  •  public static void Do(Control c, Action action) { try { if (c.InvokeRequired) { c.TopLevelControl.Invoke((Action)delegate { Do(c, action); }); } else action(); } catch (Exception ex) { //throw ex; } } 
  •  public static void Do(Control c, Action action) { try { if (c.InvokeRequired) { c.TopLevelControl.Invoke(action); } else action(); } catch (Exception ex) { //throw ex; } } 
  •  public static void Do(Control c, Action action) { try { if (c.InvokeRequired) { c.TopLevelControl.Invoke(new MethodInvoker(() => action())); } else action(); } catch (Exception ex) { //throw ex; } } 
  •  public static void Do(Control c, Action action) { try { if (c.InvokeRequired) { c.TopLevelControl.Invoke(new MethodInvoker(delegate { action(); })); } else action(); } catch (Exception ex) { //throw ex; } } 
  •  public static void Do(Control c, Action action) { try { if (c.InvokeRequired) { c.TopLevelControl.Invoke((MethodInvoker)delegate { action(); }); } else action(); } catch (Exception ex) { //throw ex; } } 

I believe approaches 1 and 2 are essentially the same and 4, 5, and 6. My questions are:

  • What is the difference between approaches (1 and 2), 3 and (4, 5 and 6)? I mean, what will happen when one processes / takes care that the other does not?

  • What is the correct way to avoid the cross thread operation error in the sense that it handles all situations, preferably brief and readable?

+1
source share
1 answer

Your β€œthird” approach above (just using Action ) is simpler and more efficient. Your other delegate approaches create a separate method (an anonymous method using the delegate keyword), which then calls your original delegate (the Action parameter), which is optional.

The third option simply uses the passed Action , which is easier.

The first option is similar, although in this case you pass values ​​that are not needed ( Control ), and you must also define a user delegate (although you can use Action<Control,Action> instead). Since the control is not used, there is no reason to add this complexity.

On the side of the note, when you are reverting inside your exception handler, it would be better to just use throw; (and not throw ex; ), as this will correctly save the stack trace:

 catch (Exception ex) { // Do whatever, ie: logging throw; } 

If you are not going to register and just plan to revert, you can completely eliminate try / catch .

+3
source

All Articles