[c#] How to call an async method from a getter or setter?

What'd be the most elegant way to call an async method from a getter or setter in C#?

Here's some pseudo-code to help explain myself.

async Task<IEnumerable> MyAsyncMethod()
{
    return await DoSomethingAsync();
}

public IEnumerable MyList
{
    get
    {
         //call MyAsyncMethod() here
    }
}

This question is related to c# async-ctp

The answer is


You can change the proerty to Task<IEnumerable>

and do something like:

get
{
    Task<IEnumerable>.Run(async()=>{
       return await getMyList();
    });
}

and use it like await MyList;


Since your "async property" is in a viewmodel, you could use AsyncMVVM:

class MyViewModel : AsyncBindableBase
{
    public string Title
    {
        get
        {
            return Property.Get(GetTitleAsync);
        }
    }

    private async Task<string> GetTitleAsync()
    {
        //...
    }
}

It will take care of the synchronization context and property change notification for you.


You can always call an asynchronous method without await if you simply want to fire and forget. But it becomes tricky when you need to wait for the result and do something with the result.

I had to call an async method in a property setter in an ASP.NET Core Blazor Server Side component. I needed to get a result from that async method and do something else.

I was stuck as I could not even use the Task.Result property in Blazor context.

So, I solved the problem by calling the .ContinueWith method which worked great. Here is a sample snippet I used.

    public bool AProperty
    {
        get => _aProperty;
        set
        {
            if (_aProperty!= value)
            {
                _aProperty= value;

                myService.UpdateAReocrdAsync().ContinueWith(previousTask =>
                {
                    int numberOfRowsAffected = previousTask.Result;
                   
                    if (numberOfRowsAffected > 0)
                    {
                        toastService.ShowSuccess($"Total {numberOfRowsAffected} rows updated.");
                    }
                    else
                    {
                        toastService.ShowError("No record was updated.");
                    }
                });
            }
        }
    }

You can't call it asynchronously, since there is no asynchronous property support, only async methods. As such, there are two options, both taking advantage of the fact that asynchronous methods in the CTP are really just a method that returns Task<T> or Task:

// Make the property return a Task<T>
public Task<IEnumerable> MyList
{
    get
    {
         // Just call the method
         return MyAsyncMethod();
    }
}

Or:

// Make the property blocking
public IEnumerable MyList
{
    get
    {
         // Block via .Result
         return MyAsyncMethod().Result;
    }
}

There is no technical reason that async properties are not allowed in C#. It was a purposeful design decision, because "asynchronous properties" is an oxymoron.

Properties should return current values; they should not be kicking off background operations.

Usually, when someone wants an "asynchronous property", what they really want is one of these:

  1. An asynchronous method that returns a value. In this case, change the property to an async method.
  2. A value that can be used in data-binding but must be calculated/retrieved asynchronously. In this case, either use an async factory method for the containing object or use an async InitAsync() method. The data-bound value will be default(T) until the value is calculated/retrieved.
  3. A value that is expensive to create, but should be cached for future use. In this case, use AsyncLazy from my blog or AsyncEx library. This will give you an awaitable property.

Update: I cover asynchronous properties in one of my recent "async OOP" blog posts.


Necromancing.
In .NET Core/NetStandard2, you can use Nito.AsyncEx.AsyncContext.Run instead of System.Windows.Threading.Dispatcher.InvokeAsync:

class AsyncPropertyTest
{

    private static async System.Threading.Tasks.Task<int> GetInt(string text)
    {
        await System.Threading.Tasks.Task.Delay(2000);
        System.Threading.Thread.Sleep(2000);
        return int.Parse(text);
    }


    public static int MyProperty
    {
        get
        {
            int x = 0;

            // https://stackoverflow.com/questions/6602244/how-to-call-an-async-method-from-a-getter-or-setter
            // https://stackoverflow.com/questions/41748335/net-dispatcher-for-net-core
            // https://github.com/StephenCleary/AsyncEx
            Nito.AsyncEx.AsyncContext.Run(async delegate ()
            {
                x = await GetInt("123");
            });

            return x;
        }
    }


    public static void Test()
    {
        System.Console.WriteLine(System.DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff"));
        System.Console.WriteLine(MyProperty);
        System.Console.WriteLine(System.DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff"));
    }


}

If you simply chose System.Threading.Tasks.Task.Run or System.Threading.Tasks.Task<int>.Run, then it wouldn't work.


I think my example below may follow @Stephen-Cleary 's approach but I wanted to give a coded example. This is for use in a data binding context for example Xamarin.

The constructor of the class - or indeed the setter of another property on which it is dependent - may call an async void that will populate the property on completion of the task without the need for an await or block. When it finally gets a value it will update your UI via the NotifyPropertyChanged mechanism.

I'm not certain about any side effects of calling a aysnc void from a constructor. Perhaps a commenter will elaborate on error handling etc.

class MainPageViewModel : INotifyPropertyChanged
{
    IEnumerable myList;

    public event PropertyChangedEventHandler PropertyChanged;

    public MainPageViewModel()
    {

        MyAsyncMethod()

    }

    public IEnumerable MyList
    {
        set
        {
            if (myList != value)
            {
                myList = value;

                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("MyList"));
                }
            }
        }
        get
        {
            return myList;
        }
    }

    async void MyAsyncMethod()
    {
        MyList = await DoSomethingAsync();
    }


}

I think that we can await for the value just returning first null and then get the real value, so in the case of Pure MVVM (PCL project for instance) I think the following is the most elegant solution:

private IEnumerable myList;
public IEnumerable MyList
{
  get
    { 
      if(myList == null)
         InitializeMyList();
      return myList;
     }
  set
     {
        myList = value;
        NotifyPropertyChanged();
     }
}

private async void InitializeMyList()
{
   MyList = await AzureService.GetMyList();
}

I thought .GetAwaiter().GetResult() was exactly the solution to this problem, no? eg:

string _Title;
public string Title
{
    get
    {
        if (_Title == null)
        {   
            _Title = getTitle().GetAwaiter().GetResult();
        }
        return _Title;
    }
    set
    {
        if (value != _Title)
        {
            _Title = value;
            RaisePropertyChanged("Title");
        }
    }
}

You can use Task like this :

public int SelectedTab
        {
            get => selected_tab;
            set
            {
                selected_tab = value;

                new Task(async () =>
                {
                    await newTab.ScaleTo(0.8);
                }).Start();
            }
        }

I review all answer but all have a performance issue.

for example in :

string _Title;
public string Title
{
    get
    {
        if (_Title == null)
        {   
            Deployment.Current.Dispatcher.InvokeAsync(async () => { Title = await getTitle(); });
        }
        return _Title;
    }
    set
    {
        if (value != _Title)
        {
            _Title = value;
            RaisePropertyChanged("Title");
        }
    }
}

Deployment.Current.Dispatcher.InvokeAsync(async () => { Title = await getTitle(); });

use dispatcher which is not a good answer.

but there is a simple solution, just do it:

string _Title;
    public string Title
    {
        get
        {
            if (_Title == null)
            {   
                Task.Run(()=> 
                {
                    _Title = getTitle();
                    RaisePropertyChanged("Title");
                });        
                return;
            }
            return _Title;
        }
        set
        {
            if (value != _Title)
            {
                _Title = value;
                RaisePropertyChanged("Title");
            }
        }
    }

When I ran into this problem, trying to run an async method synchronicity from either a setter or a constructor got me into a deadlock on the UI thread, and using an event handler required too many changes in the general design.
The solution was, as often is, to just write explicitly what I wanted to happen implicitly, which was to have another thread handle the operation and to get the main thread to wait for it to finish:

string someValue=null;
var t = new Thread(() =>someValue = SomeAsyncMethod().Result);
t.Start();
t.Join();

You could argue that I abuse the framework, but it works.