it-swarm.com.de

Wie rufe ich eine asynchrone Methode von einem Getter oder Setter auf?

Was wäre die eleganteste Methode, um eine asynchrone Methode von einem Getter oder Setter in C # aufzurufen?

Hier ist ein Pseudocode, der mir hilft, mich zu erklären.

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

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

Aufgrund meiner entkoppelten Architektur brauchte ich den Aufruf wirklich, um von der get-Methode zu stammen. Also habe ich mir die folgende Implementierung ausgedacht.

Verwendung: Titel befindet sich in einem ViewModel oder einem Objekt, das Sie statisch als Seitenressource deklarieren können. Binden Sie daran und der Wert wird aufgefüllt, ohne die Benutzeroberfläche zu blockieren, wenn getTitle () zurückgegeben wird.

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");
        }
    }
}
47
Doguhan Uluca

Es gibt keinen technischen Grund, warum async -Eigenschaften in C # nicht zulässig sind. Es war eine gezielte Entwurfsentscheidung, weil "asynchrone Eigenschaften" ein Oxymoron sind.

Eigenschaften sollten aktuelle Werte zurückgeben; Sie sollten keine Hintergrundoperationen starten.

Wenn jemand eine "asynchrone Eigenschaft" haben möchte, möchte er normalerweise eine der folgenden Eigenschaften:

  1. Eine asynchrone Methode, die einen Wert zurückgibt. Ändern Sie in diesem Fall die Eigenschaft in eine async -Methode.
  2. Ein Wert, der für die Datenbindung verwendet werden kann, jedoch asynchron berechnet/abgerufen werden muss. Verwenden Sie in diesem Fall entweder eine Factory-Methode async für das enthaltende Objekt oder eine Methode async InitAsync(). Der datengebundene Wert ist default(T), bis der Wert berechnet/abgerufen wird.
  3. Ein Wert, dessen Erstellung teuer ist, der jedoch für die zukünftige Verwendung zwischengespeichert werden sollte. In diesem Fall verwenden Sie AsyncLazyaus meinem Blog oder AsyncEx-Bibliothek . Dadurch erhalten Sie eine awaitable -Eigenschaft.

Update: Ich beschreibe asynchrone Eigenschaften in einem meiner letzten "asynchronen OOP" -Blogposts.

174
Stephen Cleary

Sie können es nicht asynchron aufrufen, da keine asynchrone Eigenschaft unterstützt wird, sondern nur asynchrone Methoden. Als solche gibt es zwei Optionen, die beide die Tatsache ausnutzen, dass asynchrone Methoden im CTP wirklich nur eine Methode sind, die Task<T> Oder Task zurückgibt:

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

Oder:

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

Ich denke, wir können abwarten, bis der Wert zuerst null und dann den tatsächlichen Wert zurückgibt. Im Fall von Pure MVVM (z. B. PCL-Projekt) halte ich Folgendes für die eleganteste Lösung:

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();
}

Ich dachte, GetAwaiter (). GetResult () war genau die Lösung für dieses Problem, nicht wahr? z.B:

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

Da sich Ihre "asynchrone Eigenschaft" in einem Ansichtsmodell befindet, können Sie AsyncMVVM verwenden:

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

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

Es kümmert sich für Sie um den Synchronisationskontext und die Benachrichtigung über Eigenschaftsänderungen.

1

Sie können Task folgendermaßen verwenden:

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

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