How to await an async private method invoked using reflection in WinRT?
Solution 1
Well you need to use the value returned by the method. Do you know the type? For example, if it's always a Task
, you could use:
await (Task) objType.GetTypeInfo()
.GetDeclaredMethod("ThePrivateMethod")
.Invoke(theObject, null);
If you don't know the return type but know it will be awaitable, you could use dynamic typing:
await (dynamic) objType.GetTypeInfo()
.GetDeclaredMethod("ThePrivateMethod")
.Invoke(theObject, null);
I would try to avoid having to call a private method by reflection in your unit tests in the first place though. Can you test it indirectly via the public (or internal) API? That's generally preferable.
Solution 2
Invoke
should return an object convertible to Task
. Just await
that.
If your private method returns void
, then you'll need a custom SynchronizationContext
, which is messy. It's better to have your methods return Task
/Task<T>
.
jokeefe
Updated on July 08, 2022Comments
-
jokeefe almost 2 years
I'm writing unit tests for a WinRT app, and I am able to invoke non-async private methods using this:
TheObjectClass theObject = new TheObjectClass(); Type objType = typeof(TheObjectClass); objType.GetTypeInfo() .GetDeclaredMethod("ThePrivateMethod") .Invoke(theObject, null);
However, if the private method in question is
async
, the code will continue execution without waiting for it to finish.How do I add
await
functionality to this? -
svick over 11 yearsBut cast to
dynamic
won't work ifGetAwaiter()
is an extension method, which is exactly the case for WinRTIAsyncAction
. -
jokeefe over 11 years@Jon Skeet: Thanks! This did it. It was a
Task
object being returned, so all I needed to do was cast it and add theawait
. I also found that you need to make the unit test method's return typeTask
as well when you make itasync
or it won't be executed by the unit test frame work. -
Jon Skeet over 10 years@Jeff: It would help if you'd give more details, like the compiler error you're getting. It may well be worth creating a new question rather than having a comment discussion about it.
-
Jon Skeet over 10 years@Jeff: That sounds like you're trying to use
await
without being in anasync
method (or lambda) - that has nothing to do with what you're trying to await. -
Jeff over 10 years@JonSkeet I think you're right. I don't have the code in front of me, but I think it might have been inside an anonymous method that wasn't marked async. Sorry for the digression, I'll erase my comments.
-
Shimmy Weitzhandler over 8 yearsIs there a way to determine if that method is
async
or not? -
Jon Skeet over 8 years@Shimmy: No, and you shouldn't need to. That's just an implementation detail. You should know whether it will perform asynchronously or not, but a method can return a
Task<T>
and perform asynchronously without being implemented via async/await. -
Shimmy Weitzhandler over 8 yearsAlight I got it now after experimenting with it a bit more. Thanks Jon! Do you ever
Thread.Sleep()
? -
Atta H. about 7 yearsIt worked for me, though i added a slight modification into it for my need
var instance = MyFactory.Instance.Create(myClassName); // custom factory
var method = instance.GetType().GetMethod(myMethodName);
await (dynamic) method.Invoke(instance, null);
-
ygoe almost 6 yearsWhen I try something like this, I get the compiler error: CS0656: Der vom Compiler angeforderte Member "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create" fehlt.
-
Jon Skeet almost 6 years@ygoe: It sounds like your project may be messed up. It's hard to say more without a lot more information. I suggest you ask a new question.
-
ygoe almost 6 years@JonSkeet Maybe this only works in WinRT and not NETStd.
-
Jon Skeet almost 6 years@ygoe: It works with .NET Standard projects running in regular .NET Core or .NET. Again, rather than trying to get the details in comments, I suggest you ask a new question with all those details.
-
Petr Voborník about 5 yearsIn Xamarin.Forms for UWP and Android it doesn't works.
-
Jon Skeet about 5 years@PetrVoborník: I'm afraid with no more information than "it doesn't works" it's unlikely that anyone will be able to help you. I suggest you create a new question with a complete example, specific context (not just "Android" but which runtime you're using) and error message.