Andreas M.
Andreas M.

Reputation: 192

Is there any way to know if a method is running being awaited from within the method?

I'm a university student but, since I like programming, I try to create a library of code that's been useful to me (something like a code base).

In the process of doing this, I started designing/writing an asynchronous method that's about to be used for interlocking a variable. My goal is to produce different result when this method is being awaited (runs synchronously) and when it isn't.

An example could be the following:


private int _lock;

public async Task<bool> Lock()
{
    if (method_is_not_being_awaited)
        return Interlocked.Exchange(ref _lock, 1) == 0;

    while (0 != Interlocked.Exchange(ref _lock, 1)) {}
    return true;

}

Is there any way to achieve such result? If yes, how?

ps: I know that I could make 2 different methods bool lock() and async Task<bool> lockAsync() but, that's not what I ask for

Upvotes: 0

Views: 116

Answers (1)

Alexei Levenkov
Alexei Levenkov

Reputation: 100527

No, it is not possible to do what you want because method must return value before any operation on result (including await) can be performed. It is not specific to async methods but rather how all code behaves in C# (and pretty much any other language).

On other hand it is pretty easy to do something that very close to what you ask - synchronously return value as soon as one tries to await the result of the method: await is essentially just call to GetAwaiter on the result and you can wire it up to alter state of your method.

Note that you can't really know what to do if method ever awaited anyway - so while you can act at moment when await is called you really can't know in advance if you should start asynchronous processing. So the best you can achieve is to do nothing in synchronous part, start asynchronous processing anyway and instantly return result when await is called (aborting/ignoring asynchronous part of the method).

Details on implementing class that can be used as result can be found in https://www.codeproject.com/Articles/5274659/How-to-Use-the-Csharp-Await-Keyword-On-Anything and https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/task-asynchronous-programming-model.

Skeleton code below shows how to implement method that does nothing unless await is called:

class MyTask
{
   public MyAwaitable GetAwaiter()
   {
     return new MyAwaitable();
   }
}

class MyAwaitable : INotifyCompletion
{
   public bool IsCompleted 
   {  
       get { return true; }
   }
   
   public int GetResult()
   {
      return 42; // this is our "result" from method.
   }
   
   public void OnCompleted (Action continuation)
   {
    // just run instantly - no need to save callback as this one is 
    // always "completed"
     continuation(); 
   }
}

MyTask F()
{
   // if your really want you can start async operation here
   // and somehow wire up MyAwaitable.IsComplete to terminate/abandon
   // asynchronous part.

  return new MyTask();
}

Upvotes: 1

Related Questions