¿Cuál sería la forma más elegante de llamar a un método asíncrono desde un getter o setter en C #?
Aquí hay un pseudocódigo para ayudar a explicarme.
async Task<IEnumerable> MyAsyncMethod()
{
return await DoSomethingAsync();
}
public IEnumerable MyList
{
get
{
//call MyAsyncMethod() here
}
}
Task<T>
, que regresará de inmediato, tenga una semántica de propiedad normal y aún permita que las cosas se traten de forma asincrónica según sea necesario.Respuestas:
No hay ninguna razón técnica para que las
async
propiedades no estén permitidas en C #. Fue una decisión de diseño intencional, porque las "propiedades asincrónicas" son un oxímoron.Las propiedades deben devolver los valores actuales; no deberían estar iniciando operaciones en segundo plano.
Por lo general, cuando alguien quiere una "propiedad asincrónica", lo que realmente quiere es uno de estos:
async
método.async
método de fábrica para el objeto que lo contiene o use unasync InitAsync()
método. El valor vinculado a los datos serádefault(T)
hasta que se calcule / recupere el valor.AsyncLazy
desde mi blog o biblioteca AsyncEx . Esto le dará unaawait
propiedad capaz.Actualización: cubro las propiedades asincrónicas en una de mis publicaciones de blog recientes "async OOP".
fuente
Dispatcher.CurrentDispatcher.Invoke(new Action(..)
?INotifyPropertyChanged
y luego decida si desea que se devuelva el valor anterior odefault(T)
mientras la actualización asincrónica está en curso.NotifyTaskCompletion
de mi proyecto AsyncEx . O puedes construir el tuyo; no es tan dificil.{Binding PropName.Result}
no es trivial para mí descubrirlo.No puede llamarlo de forma asincrónica, ya que no hay soporte de propiedad asincrónica, solo métodos asincrónicos. Como tal, hay dos opciones, ambas aprovechando el hecho de que los métodos asincrónicos en el CTP son realmente solo un método que devuelve
Task<T>
oTask
:O:
fuente
private async void SetupList() { MyList = await MyAsyncMethod(); }
este que haría que MyList se establezca (y luego se vincule automáticamente, si implementa INPC) tan pronto como se complete la operación asíncrona ...getTitle()
simultánea ...Realmente necesitaba que la llamada se originara en el método get, debido a mi arquitectura desacoplada. Entonces se me ocurrió la siguiente implementación.
Uso: El título está en un ViewModel o un objeto que podría declarar estáticamente como un recurso de página. Vincúlelo y el valor se completará sin bloquear la interfaz de usuario, cuando getTitle () regrese.
fuente
Creo que podemos esperar que el valor devuelva primero nulo y luego obtener el valor real, por lo que en el caso de Pure MVVM (proyecto PCL, por ejemplo), creo que la siguiente es la solución más elegante:
fuente
CS4014: Async method invocation without an await expression
async void
solo para manejadores de nivel superior y similares". Creo que esto puede calificar como "y sus similares".Puedes usar
Task
así:fuente
Pensé .GetAwaiter (). GetResult () era exactamente la solución a este problema, ¿no? p.ej:
fuente
.Result
: no es asíncrono y puede provocar puntos muertos.Como su "propiedad asíncrona" está en un modelo de vista, puede usar AsyncMVVM :
Se encargará del contexto de sincronización y la notificación de cambio de propiedad.
fuente
Nigromancia
En .NET Core / NetStandard2, puede usar en
Nito.AsyncEx.AsyncContext.Run
lugar deSystem.Windows.Threading.Dispatcher.InvokeAsync
:Si simplemente elige
System.Threading.Tasks.Task.Run
oSystem.Threading.Tasks.Task<int>.Run
, entonces no funcionaría.fuente
Creo que mi ejemplo a continuación puede seguir el enfoque de @ Stephen-Cleary, pero quería dar un ejemplo codificado. Esto es para usar en un contexto de enlace de datos, por ejemplo Xamarin.
El constructor de la clase, o el configurador de otra propiedad de la que depende, puede llamar a un vacío asíncrono que llenará la propiedad al completar la tarea sin la necesidad de esperar o bloquear. Cuando finalmente obtenga un valor, actualizará su interfaz de usuario a través del mecanismo NotifyPropertyChanged.
No estoy seguro de los efectos secundarios de llamar a un vacío de Aysnc desde un constructor. Tal vez un comentarista elaborará el manejo de errores, etc.
fuente
Cuando me encontré con este problema, intentar ejecutar una sincronía de método asíncrono desde un instalador o un constructor me metió en un punto muerto en el hilo de la interfaz de usuario, y el uso de un controlador de eventos requirió demasiados cambios en el diseño general.
La solución era, como suele ser, simplemente escribir explícitamente lo que quería que sucediera implícitamente, que era que otro hilo manejara la operación y que el hilo principal esperara a que terminara:
Se podría argumentar que abusé del marco, pero funciona.
fuente
Reviso todas las respuestas pero todas tienen un problema de rendimiento.
por ejemplo en:
Deployment.Current.Dispatcher.InvokeAsync (async () => {Title = await getTitle ();});
use el despachador que no es una buena respuesta.
pero hay una solución simple, solo hazlo:
fuente
Puedes cambiar la proactividad a
Task<IEnumerable>
y hacer algo como:
y úsalo como espera MyList;
fuente