[C#] ¿Pueden los constructores ser asincrónicos?


Answers

Como no es posible crear un constructor asíncrono, utilizo un método asíncrono estático que devuelve una instancia de clase creada por un constructor privado. Esto no es elegante, pero funciona bien.

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

    //static async method that behave like a constructor       
    async public static Task<ViewModel> BuildViewModelAsync()  
    {       
     ObservableCollection<TData> tmpData = await GetDataTask();  
     return new ViewModel(tmpData);
    }       

    // private constructor called by the async method
    private ViewModel(ObservableCollection<TData> Data)
    {
     this.Data=Data;   
    }
   }  
Question

Tengo un proyecto de Silverlight en el que trato de completar algunos datos en un constructor:

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

Lamentablemente, recibo un error:

El modificador async no es válido para este artículo

Por supuesto, si envuelvo en un método estándar y lo llamo desde el constructor:

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

funciona bien. Del mismo modo, si uso la vieja forma de adentro hacia afuera

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

Eso también funciona Me preguntaba por qué no podemos llamar en await directamente desde un constructor. Probablemente haya muchos (incluso obvios) casos extremos y razones en contra, simplemente no puedo pensar en ninguno. También busqué una explicación, pero parece que no puedo encontrar ninguna.




Me preguntaba por qué no podemos llamar en await directamente desde un constructor.

Creo que la respuesta breve es simple: porque el equipo .Net no ha programado esta característica.

Creo que con la sintaxis correcta esto podría implementarse y no debería ser demasiado confuso o propenso a errores. Creo que la blog Stephen Cleary en el blog y varias otras respuestas aquí han señalado implícitamente que no hay una razón fundamental en su contra, y más que eso: resolvieron esa falta con soluciones provisionales. La existencia de estas soluciones relativamente simples es probablemente una de las razones por las que esta característica aún no se ha implementado.




No estoy familiarizado con la palabra clave async (¿es esto específico para Silverlight o una nueva característica en la versión beta de Visual Studio?), Pero creo que puedo darle una idea de por qué no puede hacer esto.

Si lo hago:

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

o puede que no se realice la inicialización antes de que se ejecute la siguiente línea de código. No se puede asignar una instancia de su objeto hasta que se complete su constructor, y hacer que el constructor asincrónico no cambie eso, ¿cuál sería el punto? Sin embargo, podría llamar a un método asíncrono desde su constructor y luego su constructor podría completar y obtendría la creación de instancias mientras el método asíncrono sigue haciendo lo que sea necesario para configurar su objeto.




Utilizo este truco fácil.

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
    */
  }
}



si hace el constructor asíncrono, después de crear un objeto, puede tener problemas como valores nulos en lugar de objetos de instancia. Por ejemplo;

MyClass instance = new MyClass();
instance.Foo(); // null exception here

Es por eso que no permiten esto, supongo.