Windowscommunitytoolkit: NullException when using Dispatcher.AwaitableRunAsync with Action

Created on 11 Nov 2016  路  29Comments  路  Source: windows-toolkit/WindowsCommunityToolkit

bug helpers

Most helpful comment

Ohhh... now that makes sense now... you got me for a solid hour there hahahahaha. Thanks for fixing this, I appreciate it. :)

All 29 comments

taskCompletionSource.SetResult(await function().ConfigureAwait(false)); will raise NulLException if function return null

Ping @Code-ScottLe

Ooohf. Dang. I'll get on it after work.

@deltakosh Do you have an example of this failing?

I'm Publishing a fix in 2 mins but what cause it

int crossThreadReturnedValue = await Task.Run(async () =>
{
int returnedFromUIThread = await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
{
NormalTextBlock.Text = "Updated from a random thread!";
return null;
});

            return returnedFromUIThread + 1;
        });

int returnedFromUIThread = await DispatcherHelper.ExecuteOnUIThreadAsync(() => { NormalTextBlock.Text = "Updated from a random thread!"; return null; });

This call doesn't specified the return value type T, this must have been compile-time error isn't it? Or maybe i'm missing something here

No the return type is Task :) not the T

I was wondering how this happening until I saw Func of Task of T , Task is the return type :) that's why it allowed null.

but in the code above, the call is awaited the returned Task and try to assign the returned value to an int, which should be caught by Intellisense / Compiler right? Or should i ignore that part ? :)

lol :) you're totally right maybe we should report this to the VS team.

Or maybe it is designed to be like that.

Ya, i was like, "wait what?, how does one that even pass the compiler!?"

The function argument shouldn't be null at any given call, unless they especially pass null in, and await can deal with null just fine I believe.

No the Task that is returned from the function is the Null not the func it self and that's why when the task(Null).configureAwait will throw a null reference :)

Oh! I see. So the entire returned Task itself is null? In which case does that happen?

int returnedFromUIThread = await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
{
NormalTextBlock.Text = "Updated from a random thread!";
return null;
});

Hmm, i'm still scratching my head over here on how this call ended up using the Func<Task> Overload.

() => { NormalTextBlock.Text = "Updated from a random thread!";
return null;});

is an Action, which then be Func<object> when it get down to AwaitableRunAsync overload that use Func<T>, which shouldn't have any await and async, Somebody enlighten me please haha :)

I was just like that the moment I saw it :) but after investigation I noticed the Task<int> and the return null refere to the task not the int :)

So is the returned value of the call above (not the lambda) is Task<int> ?

Yes :)

If that is the case, then i don't get it why the lambda passed compiling then, int is not nullable without the verify specific int? declaration and the return null statement must have been caught on compile time. Any ideas?

ping @lukasf

let me explain it from my point of view :)
Method ExecuteOnUIThreadAsync<T>(Func<Task<T>> function) tasks a func of task of T (int) right so whatever is return from this function is a Task of T or int, if you returned an int (1) as the main page example, it returns Task as its result is 1 and we can have this result once we await.
but what if you returned a null ? should it refer to the generic object which is int or the Task it self and I see that VS and CLR took the path Task is the null not the generic object it self is the null which we could have an open discussion about which path should be followed :)

Yeah, i understand your reasoning. So it is almost like :

"hey, i am expecting a function that return either int or Task<int>. This lambda return null and int is not nullable, so let's pick the overload that has the signature of Task<int> instead" .

But the call is a straight forward DispatcherHelper.ExecuteOnUIThreadAsync without the generic part <T>. So there are only 2 overloads that can be called upon. One uses Action and one uses Func<Task> . And somehow this ended up returning a Task<int> that can be awaited with an int is beyond me.

Thank you guys! it was an interesting one :)

heheh yes :) for a second I thought VS has a bug :D

No, the code uses the generic one :)
int returnedFromUIThread = await DispatcherHelper.ExecuteOnUIThreadAsync<int>(() => { NormalTextBlock.Text = "Updated from a random thread!"; return 1; });

but I see that github removed the greater than sign :)

Ohhh... now that makes sense now... you got me for a solid hour there hahahahaha. Thanks for fixing this, I appreciate it. :)

You're welcome :)

Wow, nice one! Pretty weird but somehow it makes sense, from the compiler's point of view... :)

Was this page helpful?
0 / 5 - 0 ratings