Guess so
. In any case, what I would have expected is some smart,
short keyword or something, like this:
// On non GUI thread, call GUI method:
SomeGuiObject.DoSomething() as AsyncGuiCall;
Well, I see the appeal of the syntax. Unfortunately, a) that would
require explicit support in the C# language (which otherwise doesn't
really "know" anything about the Forms namespace), and b) doesn't
translate well for situations where the method you want to call isn't
actually part of the GUI control class.
Besides, assuming you've already got a method that does the "something"
you want, is the above so much harder than writing:
SomeGuiObject.Invoke(SomeGuiObject.DoSomething);
?
Or in the specific example you had:
SomeGuiObject.Invoke(SomeGuiObject.SetPercentage, new object[]
{ progress } );
And all that assumes that the code isn't actually in the "SomeGuiObject"
class. If it was (and in your case it looks like it is), you could just
have this:
Invoke(SetPercentage, new object[] { progress } );
The parameter passing gets a _little_ messy, but otherwise it's pretty
straightforward. I only made the suggestion I did because I prefer for
the caller to not even have to worry about the cross-thread issue. But if
you're going to embed that information in the call itself, you might as
well use the one-line approaches above.
I guess that your pattern (assuming you need to invoke anyway) will
help me as well, making my code more readable (albeit at the expense
of some overhead).
Assuming you're using Invoke() in the usual way, there won't be _any_
overhead. It's only in the unusual situation where you are using the same
method for in-thread and cross-thread purposes that there'd be the
overhead, and I really believe the overhead will be minimal. You could
measure it if it's important to you, but given all the other stuff that
has to happen when you call a method that requires invoking in the first
place, the minimal work that the Invoke() method has to do in order to
deal with the in-thread case versus the cross-thread case isn't likely to
even show up on the radar.
The reason I was stunned I guess was because I don't see why all this
is even necessary: if the framework tells me "not allowed from non-GUI
thread" I just want it to use the damn GUI thread by default
Well, I think that's an especially legitimate question. In unmanaged
code, the rough equivalent would be the issues surrounding the use of
SendMessage(). I believe that the .NET requirement essentially inherits
from the same unmanaged Windows requirement that code using a window
class's window proc always execute on the thread that owns the window.
The requirement has to do with keeping access to the window data
structures thread-safe.
But in unmanaged code, if you call SendMessage() from the wrong thread,
Windows automatically marshals the call over to the right thread for you.
It basically does the Invoke()-like behavior on your behalf.
I'm not really clear on why .NET didn't take a similar approach. The
issue should only really come up for class to Control-derived class
methods that ultimately result in a call to SendMessage() and those should
get marshaled over to the right thread anyway.
I suspect that there is in fact a decent explanation, but it bugs me that
this explanation isn't immediately apparent. One thing that comes to mind
is that the concern was not that they couldn't make the thread change
automatic, but that doing so would lead to programmer confusion, as they
wonder "why the heck is this code executing on a completely different
thread?" for those cases where calling a Control-derived class method
winds up going through SendMessage() and then causing some client code to
then be executed (for example, setting the Text property, while subscribed
to a TextChanged event, assuming that the Control-derived class raises the
TextChanged event directly from the window proc when the window message
setting the text is sent).
But all the explanations I've seen don't discuss that possibility. They
all say that .NET _can't_ deal with the issue, rather than that it's just
a design decision to keep the coding simpler and safer.
Ah well...for now, one of the great mysteries of .NET (at least, to
me...if anyone's reading this and they know the answer, please post it!
And with great detail...no hand-waving, please
).
Pete