Chiama il metodo asincrono nel costruttore?

Riepilogo : vorrei chiamare un metodo asincrono in un costruttore. È ansible?

Dettagli : ho un metodo chiamato getwritings() che analizza i dati JSON. Tutto funziona bene se chiamo getwritings() in un metodo async e se ne getwritings() a sinistra. Tuttavia, quando creo LongListView nella mia pagina e provo a popolarlo, sto trovando che getWritings() restituisce sorprendentemente null e LongListView è vuoto.

Per risolvere questo problema, ho provato a modificare il tipo restituito da getWritings() all’attività Task<List> e quindi a recuperare il risultato nel costruttore tramite getWritings().Result . Tuttavia, farlo finisce per bloccare il thread dell’interfaccia utente.

 public partial class Page2 : PhoneApplicationPage { List writings; public Page2() { InitializeComponent(); getWritings(); } private async void getWritings() { string jsonData = await JsonDataManager.GetJsonAsync("1"); JObject obj = JObject.Parse(jsonData); JArray array = (JArray)obj["posts"]; for (int i = 0; i < array.Count; i++) { Writing writing = new Writing(); writing.content = JsonDataManager.JsonParse(array, i, "content"); writing.date = JsonDataManager.JsonParse(array, i, "date"); writing.image = JsonDataManager.JsonParse(array, i, "url"); writing.summary = JsonDataManager.JsonParse(array, i, "excerpt"); writing.title = JsonDataManager.JsonParse(array, i, "title"); writings.Add(writing); } myLongList.ItemsSource = writings; } } 

    La soluzione migliore è riconoscere la natura asincrona del download e del design per esso.

    In altre parole, decidi come dovrebbe apparire la tua applicazione mentre i dati vengono scaricati. Chiedi al costruttore della pagina di configurare la vista e avviare il download. Al termine del download, aggiornare la pagina per visualizzare i dati.

    Ho un post sul blog sui costruttori asincroni che potresti trovare utile. Inoltre, alcuni articoli MSDN; uno sull’assegnazione dei dati asincrona (se si sta utilizzando MVVM) e un altro sulle best practice asincrone (ovvero, si dovrebbe evitare il async void ).

    Puoi anche fare così:

     Task.Run(() => this.FunctionAsync()).Wait(); 

    Mi piacerebbe condividere uno schema che ho usato per risolvere questo tipo di problemi. Funziona piuttosto bene, penso. Certo, funziona solo se hai il controllo su ciò che chiama il costruttore. Esempio di seguito

     public class MyClass { public static async Task Create() { var myClass = new MyClass(); await myClass.Initialize(); return myClass; } private MyClass() { } private async Task Initialize() { await Task.Delay(1000); // Do whatever asynchronous work you need to do } } 

    In sostanza, ciò che facciamo è rendere privato il costruttore e creare il nostro metodo pubblico asincrono statico che è responsabile della creazione di un’istanza di MyClass. Rendendo il costruttore privato e mantenendo il metodo statico all’interno della stessa class, abbiamo fatto in modo che nessuno potesse “accidentalmente” creare un’istanza di questa class senza chiamare i metodi di inizializzazione appropriati. Tutta la logica attorno alla creazione dell’object è ancora contenuta all’interno della class (solo all’interno di un metodo statico).

     var myClass1 = new MyClass() // Cannot be done, the constructor is private var myClass2 = MyClass.Create() // Returns a Task that promises an instance of MyClass once it's finished var myClass3 = await MyClass.Create() // asynchronously creates and initializes an instance of MyClass 

    Attuato nello scenario attuale assomiglierebbe a qualcosa:

     public partial class Page2 : PhoneApplicationPage { public static async Task Create() { var page = new Page2(); await page.getWritings(); return page; } List writings; private Page2() { InitializeComponent(); } private async Task getWritings() { string jsonData = await JsonDataManager.GetJsonAsync("1"); JObject obj = JObject.Parse(jsonData); JArray array = (JArray)obj["posts"]; for (int i = 0; i < array.Count; i++) { Writing writing = new Writing(); writing.content = JsonDataManager.JsonParse(array, i, "content"); writing.date = JsonDataManager.JsonParse(array, i, "date"); writing.image = JsonDataManager.JsonParse(array, i, "url"); writing.summary = JsonDataManager.JsonParse(array, i, "excerpt"); writing.title = JsonDataManager.JsonParse(array, i, "title"); writings.Add(writing); } myLongList.ItemsSource = writings; } } 

    E invece di fare

     var page = new Page2(); 

    Lo faresti

     var page = await Page2.Create(); 

    Prova a sostituire questo:

     myLongList.ItemsSource = writings; 

    con questo

     Dispatcher.BeginInvoke(() => myLongList.ItemsSource = writings); 

    Potresti provare AsyncMVVM .

    Page2.xaml:

        

    Page2.xaml.cs:

     public partial class Page2 { InitializeComponent(); DataContext = new ViewModel2(); } 

    ViewModel2.cs:

     public class ViewModel2: AsyncBindableBase { public IEnumerable Writings { get { return Property.Get(GetWritingsAsync); } } private async Task> GetWritingsAsync() { string jsonData = await JsonDataManager.GetJsonAsync("1"); JObject obj = JObject.Parse(jsonData); JArray array = (JArray)obj["posts"]; for (int i = 0; i < array.Count; i++) { Writing writing = new Writing(); writing.content = JsonDataManager.JsonParse(array, i, "content"); writing.date = JsonDataManager.JsonParse(array, i, "date"); writing.image = JsonDataManager.JsonParse(array, i, "url"); writing.summary = JsonDataManager.JsonParse(array, i, "excerpt"); writing.title = JsonDataManager.JsonParse(array, i, "title"); yield return writing; } } } 

    Per dirla semplicemente, riferendosi a Stephen Cleary https://stackoverflow.com/a/23051370/267000

    la tua pagina sulla creazione dovrebbe creare attività nel costruttore e dovresti dichiararle come membri della class o metterle nel tuo gruppo di attività.

    I tuoi dati vengono recuperati durante queste attività, ma queste attività dovrebbero essere attese nel codice, ad esempio su alcune manipolazioni dell’interfaccia utente, ad esempio Ok, clic, ecc.

    Ho sviluppato app di questo tipo in WP, all’inizio abbiamo creato un sacco di attività.