Alors que LINQ n'a pas vraiment cela en soi, le framework lui-même le fait... Vous pouvez facilement créer votre propre exécuteur de requête asynchrone en environ 30 lignes... En fait, je viens de le composer pour vous :)
EDIT : En écrivant ceci, j'ai découvert pourquoi ils ne l'ont pas implémenté. Il ne peut pas gérer les types anonymes car ils sont locaux. Ainsi, vous n'avez aucun moyen de définir votre fonction de rappel. C'est une chose assez importante car beaucoup de trucs linq to sql les crée dans la clause select. Toutes les suggestions ci-dessous subissent le même sort, donc je pense toujours que celui-ci est le plus facile à utiliser!
EDIT : La seule solution est de ne pas utiliser de types anonymes. Vous pouvez déclarer le rappel comme prenant simplement IEnumerable (pas d'arguments de type) et utiliser la réflexion pour accéder aux champs (ICK!!). Une autre façon serait de déclarer le rappel comme "dynamique"... oh... attendez... Ce n'est pas encore sorti. :) C'est un autre exemple de comment dynamic pourrait être utilisé. Certains pourraient appeler cela de l'abus.
Insérez ceci dans votre bibliothèque d'utilitaires :
public static class AsynchronousQueryExecutor
{
public static void Call(IEnumerable query, Action> callback, Action errorCallback)
{
Func, IEnumerable> func =
new Func, IEnumerable>(InnerEnumerate);
IEnumerable result = null;
IAsyncResult ar = func.BeginInvoke(
query,
new AsyncCallback(delegate(IAsyncResult arr)
{
try
{
result = ((Func, IEnumerable>)((AsyncResult)arr).AsyncDelegate).EndInvoke(arr);
}
catch (Exception ex)
{
if (errorCallback != null)
{
errorCallback(ex);
}
return;
}
//les erreurs à l'intérieur d'ici sont le problème du rappel
//Je pense que ce serait confus de les signaler
callback(result);
}),
null);
}
private static IEnumerable InnerEnumerate(IEnumerable query)
{
foreach (var item in query) //le méthode bloque ici pendant l'exécution de la requête
{
yield return item;
}
}
}
Et vous pourriez l'utiliser comme ceci :
class Program
{
public static void Main(string[] args)
{
//cela pourrait être votre requête linq
var qry = TestSlowLoadingEnumerable();
//Nous lançons l'appel et lui donnons notre délégué de rappel
//et un délégué vers un gestionnaire d'erreur
AsynchronousQueryExecutor.Call(qry, HandleResults, HandleError);
Console.WriteLine("L'appel a commencé sur un thread séparé, l'exécution s'est poursuivie");
Console.ReadLine();
}
public static void HandleResults(IEnumerable results)
{
//les résultats sont disponibles ici
foreach (var item in results)
{
Console.WriteLine(item);
}
}
public static void HandleError(Exception ex)
{
Console.WriteLine("erreur");
}
//juste une énumération d'exemple à chargement lent
public static IEnumerable TestSlowLoadingEnumerable()
{
Thread.Sleep(5000);
foreach (var i in new int[] { 1, 2, 3, 4, 5, 6 })
{
yield return i;
}
}
}
Je vais maintenant le mettre sur mon blog, assez pratique.