476 Stimmen

Können Konstruktoren asynchron sein?

Ich habe ein Projekt, wo ich versuche, einige Daten in einem Konstruktor zu füllen:

public class ViewModel
{
    public ObservableCollection<TData> Data { get; set; }

    async public ViewModel()
    {
        Data = await GetDataTask();
    }

    public Task<ObservableCollection<TData>> GetDataTask()
    {
        Task<ObservableCollection<TData>> task;

        //Create a task which represents getting the data
        return task;
    }
}

Leider erhalte ich eine Fehlermeldung:

Der Modifikator async ist für diesen Artikel nicht gültig

Natürlich, wenn ich eine Standardmethode einpacke und diese vom Konstruktor aus aufrufe:

public async void Foo()
{
    Data = await GetDataTask();
}

Es funktioniert gut. Ebenso, wenn ich die alte Methode von innen nach außen verwende

GetData().ContinueWith(t => Data = t.Result);

Das funktioniert auch. Ich habe mich nur gefragt, warum wir nicht anrufen können await direkt aus einem Konstruktor heraus. Es gibt wahrscheinlich viele (auch offensichtliche) Randfälle und Gründe dagegen, mir fallen nur keine ein. Ich habe auch nach einer Erklärung gesucht, aber ich kann keine finden.

-1voto

Dirk Boer Punkte 7750

Bitte streichen Sie diese Sprachanfrage:

https://github.com/dotnet/csharplang/discussions/419

Die Menge an Boilerplate-Code, die jeder schreiben muss, um ein vollständig initialisiertes asynchrones Objekt zu haben, ist verrückt und völlig entgegengesetzt zum Trend in C# (weniger Boilerplate).

-2voto

tomcat Punkte 1602

Ich würde etwa so vorgehen.

 public class MyViewModel
    {
            public MyDataTable Data { get; set; }
            public MyViewModel()
               {
                   loadData(() => GetData());
               }
               private async void loadData(Func<DataTable> load)
               {
                  try
                  {
                      MyDataTable = await Task.Run(load);
                  }
                  catch (Exception ex)
                  {
                       //log
                  }
               }
               private DataTable GetData()
               {
                    DataTable data;
                    // get data and return
                    return data;
               }
    }

Das ist die beste Lösung, die ich für Konstrukteure finden kann.

-2voto

omri tsufim Punkte 31

Können Sie einen Wrapper erstellen und einen Funktor einfügen, der den Konstruktor darstellt:

class AsyncConstruct<T>
    where T: class
{
    private readonly Task<T> m_construction;
    private T m_constructed;
    public AsyncConstruct(Func<T> createFunc)
    {
        m_constructed = null;
        m_construction = Task.Run(()=>createFunc());
    }

    public T Get()
    {
        if(m_constructed == null)
        {
            m_constructed = m_construction.Result;
        }
        return m_constructed;
    }
}

-5voto

user1630939 Punkte 101

Ich wende diesen einfachen Trick an.

public sealed partial class NamePage
{
  private readonly Task _initializingTask;

  public NamePage()
  {
    _initializingTask = Init();
  }

  private async Task Init()
  {
    /*
    Initialization that you need with await/async stuff allowed
    */
  }
}

-6voto

Brandon Moore Punkte 8322

Ich bin mit dem async-Schlüsselwort nicht vertraut (ist dies spezifisch für Silverlight oder eine neue Funktion in der Beta-Version von Visual Studio?), aber ich denke, ich kann Ihnen eine Vorstellung davon geben, warum dies nicht möglich ist.

Wenn ich es tue:

var o = new MyObject();
MessageBox(o.SomeProperty.ToString());

o ist möglicherweise nicht fertig mit der Initialisierung, bevor die nächste Codezeile läuft. Eine Instanziierung Ihres Objekts kann nicht zugewiesen werden, bevor Ihr Konstruktor abgeschlossen ist, und wenn Sie den Konstruktor asynchron machen, würde sich daran nichts ändern, was wäre also der Sinn? Sie könnten jedoch eine asynchrone Methode von Ihrem Konstruktor aus aufrufen, und dann könnte Ihr Konstruktor abgeschlossen werden, und Sie würden Ihre Instanziierung erhalten, während die asynchrone Methode noch tut, was immer sie tun muss, um Ihr Objekt einzurichten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X