Domanda

I am starting to create some classes who will fire asynchronous operations and I want the client to register a callback to receive some results. Finally I reached the following code. It is just an example, and I would like to know if there is a better way of doing it using TaskFactory and Action<>, Func<>

Here is the client basic example:

Client client2 = new Client();
client2.GetClientList(ClientCallBack);


private static void ClientCallBack(List<Client> listado)
{ 
  //Receive the list result and do some stuff in UI      
}

Here is the Client class GetCLientList asynchronous example:

public void GetClientList(Action<List<Client>> Callback)
{
  List<Client> listado=null;

  Task.Factory.StartNew(() =>
    {
      listado = new List<Client>{
        new Client{ apellidos="Landeras",nombre="Carlos",edad=25},
        new Client{ apellidos="Lopez", nombre="Pepe", edad=22},
        new Client{ apellidos="Estevez", nombre="Alberto", edad=28}
      };

    //Thread.Sleep to simulate some load
    System.Threading.Thread.Sleep(4000);
  }).ContinueWith((prevTask) =>
    {
      Callback(listado);
    }
  );
}

Is there a better way of doing it?. I know I can return Task from my function and register the continueWith in client side, but I want to wrap it inside the class.

EDIT

I'm posting another example. I was trying to make sync/async versions of a webrequest. Is this approach correct?:

public string ExecuteRequest(string url)
{
  HttpWebRequest httpwebrequest = (HttpWebRequest) WebRequest.Create(url);
  HttpWebResponse httpwebresponse = (HttpWebResponse) httpwebrequest.GetResponse();

  using (StreamReader sr = new StreamReader(httpwebresponse.GetResponseStream()))
  {
    return sr.ReadToEnd();
  }
}

public void ExecuteRequestAsync(string uri,Action<string> callbackResult)
{
  Task.Factory.StartNew(() => ExecuteRequest(uri), CancellationToken.None)
    .ContinueWith((task) => callbackResult(task.Result));           
}
È stato utile?

Soluzione

First, your method doesn't seem to be actually asynchronous, so you're not going to gain much from making it look like one. If the user of your method decides to run it on another thread, they can do it themselves.

Second, if you can use C# 5.0, you should follow the Task-based asynchronous pattern, to make your method easier to use. With that (and assuming you have a reason to ignore my first point above), your code could look like this:

public Task<List<Client>> GetClientListAsync()
{
    return Task.Run(() =>
    {
        var list = new List<Client>
        {
            new Client { apellidos="Landeras", nombre="Carlos", edad=25 },
            new Client { apellidos="Lopez", nombre="Pepe", edad=22 },
            new Client { apellidos="Estevez", nombre="Alberto", edad=28 }
        };

        //Thread.Sleep to simulate some load
        System.Threading.Thread.Sleep(4000);

        return list;
    });
}

Or, if you wanted to make your code actually asynchronous:

public async Task<List<Client>> GetClientListAsync()
{
    var list = new List<Client>
    {
        new Client { apellidos="Landeras", nombre="Carlos", edad=25 },
        new Client { apellidos="Lopez", nombre="Pepe", edad=22 },
        new Client { apellidos="Estevez", nombre="Alberto", edad=28 }
    };

    //Task.Delay() to simulate some load
    await Task.Delay(4000);

    return list;
}

In both cases, you could then use this method without using callbacks from an async method like this:

var client = new Client();
var list = await client.GetClientListAsync();
//Receive the list result and do some stuff in UI

Third, if you didn't want to (or couldn't) use async-await, then your code is close, but quite right. The problem is that the callback won't actually execute on the UI thread. For that, you would need to use TaskScheduler.FromCurrentSynchronizationContext().

Also, your design where Client has a GetClientList() method seems suspicious to me. Such method probably belongs to some sort of repository object, not to Client.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top