Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何编写异步LINQ查询?_C#_Linq_Linq To Sql_Asynchronous - Fatal编程技术网

C# 如何编写异步LINQ查询?

C# 如何编写异步LINQ查询?,c#,linq,linq-to-sql,asynchronous,C#,Linq,Linq To Sql,Asynchronous,在阅读了大量与LINQ相关的内容后,我突然意识到没有文章介绍如何编写异步LINQ查询 假设我们使用LINQtoSQL,下面的语句很清楚。但是,如果SQL数据库响应缓慢,那么使用此代码块的线程将受到阻碍 var result = from item in Products where item.Price > 3 select item.Name; foreach (var name in result) { Console.WriteLine(name); } 当前的LINQ查询

在阅读了大量与LINQ相关的内容后,我突然意识到没有文章介绍如何编写异步LINQ查询

假设我们使用LINQtoSQL,下面的语句很清楚。但是,如果SQL数据库响应缓慢,那么使用此代码块的线程将受到阻碍

var result = from item in Products where item.Price > 3 select item.Name;
foreach (var name in result)
{
    Console.WriteLine(name);
}
当前的LINQ查询规范似乎不支持这一点

有没有办法在LINQ中进行异步编程?它的工作原理就像有回调一样
当结果在I/O上没有任何阻塞延迟就可以使用时发出通知。

虽然LINQ本身没有这种功能,但框架本身有。。。您可以轻松地将自己的异步查询执行器滚动到30行左右。。。事实上,我只是为你准备了这个:)

EDIT:通过写这篇文章,我发现了他们为什么没有实现它。它无法处理匿名类型,因为它们的作用域是本地的。因此,您无法定义回调函数。这是一件非常重要的事情,因为很多linq到sql的东西都是在select子句中创建回调函数的。下面的任何一个建议都会遭受同样的命运,所以我仍然认为这一个是最容易使用的

编辑:唯一的解决方案是不使用匿名类型。您可以将回调声明为只接受IEnumerable(无类型args),并使用反射来访问字段(ICK!!)。另一种方法是将回调声明为“动态”。。。哦等待那还没有出来。:)这是如何使用dynamic的另一个不错的例子。有些人可能称之为虐待

将其放入实用程序库:

public static class AsynchronousQueryExecutor
{
    public static void Call<T>(IEnumerable<T> query, Action<IEnumerable<T>> callback, Action<Exception> errorCallback)
    {
        Func<IEnumerable<T>, IEnumerable<T>> func =
            new Func<IEnumerable<T>, IEnumerable<T>>(InnerEnumerate<T>);
        IEnumerable<T> result = null;
        IAsyncResult ar = func.BeginInvoke(
                            query,
                            new AsyncCallback(delegate(IAsyncResult arr)
                            {
                                try
                                {
                                    result = ((Func<IEnumerable<T>, IEnumerable<T>>)((AsyncResult)arr).AsyncDelegate).EndInvoke(arr);
                                }
                                catch (Exception ex)
                                {
                                    if (errorCallback != null)
                                    {
                                        errorCallback(ex);
                                    }
                                    return;
                                }
                                //errors from inside here are the callbacks problem
                                //I think it would be confusing to report them
                                callback(result);
                            }),
                            null);
    }
    private static IEnumerable<T> InnerEnumerate<T>(IEnumerable<T> query)
    {
        foreach (var item in query) //the method hangs here while the query executes
        {
            yield return item;
        }
    }
}
公共静态类AsynchronousQueryExecutor
{
公共静态void调用(IEnumerable查询、Action回调、Action errorCallback)
{
Func Func=
新函数(内部枚举);
IEnumerable结果=null;
IAsyncResult ar=func.BeginInvoke(
查询
新的异步回调(委托(IAsyncResult arr)
{
尝试
{
结果=((Func)((AsyncResult)arr.AsyncDelegate.EndInvoke(arr);
}
捕获(例外情况除外)
{
if(errorCallback!=null)
{
错误回调(ex);
}
返回;
}
//这里的内部错误是回调问题
//我认为报告他们会令人困惑
回调(结果);
}),
无效);
}
私有静态IEnumerable InnerEnumerate(IEnumerable查询)
{
foreach(查询中的var项)//当查询执行时,方法挂起在这里
{
收益回报项目;
}
}
}
你可以这样使用它:

class Program
{

    public static void Main(string[] args)
    {
        //this could be your linq query
        var qry = TestSlowLoadingEnumerable();

        //We begin the call and give it our callback delegate
        //and a delegate to an error handler
        AsynchronousQueryExecutor.Call(qry, HandleResults, HandleError);

        Console.WriteLine("Call began on seperate thread, execution continued");
        Console.ReadLine();
    }

    public static void HandleResults(IEnumerable<int> results)
    {
        //the results are available in here
        foreach (var item in results)
        {
            Console.WriteLine(item);
        }
    }

    public static void HandleError(Exception ex)
    {
        Console.WriteLine("error");
    }

    //just a sample lazy loading enumerable
    public static IEnumerable<int> TestSlowLoadingEnumerable()
    {
        Thread.Sleep(5000);
        foreach (var i in new int[] { 1, 2, 3, 4, 5, 6 })
        {
            yield return i;
        }
    }

}
public async Task WriteNamesToConsoleAsync(string connectionString, CancellationToken token = default(CancellationToken))
{
    using (var ctx = new DataContext(connectionString))
    {
        var query = from item in Products where item.Price > 3 select item.Name;
        var result = await ExecuteAsync(query, ctx, token);
        foreach (var name in result)
        {
            Console.WriteLine(name);
        }
    }
}
类程序
{
公共静态void Main(字符串[]args)
{
//这可能是您的linq查询
var qry=TestSlowLoadingEnumerable();
//我们开始调用并将回调委托给它
//以及对错误处理程序的委托
异步QueryExecutor.Call(qry、HandleResults、HandleError);
WriteLine(“调用开始于单独的线程,执行继续”);
Console.ReadLine();
}
公共静态无效句柄结果(IEnumerable结果)
{
//结果可以在这里找到
foreach(结果中的var项目)
{
控制台写入线(项目);
}
}
公共静态无效句柄错误(例外情况除外)
{
控制台写入线(“错误”);
}
//只是一个延迟加载枚举的示例
公共静态IEnumerable测试slowLoadingEnumerable()
{
睡眠(5000);
foreach(新int[]{1,2,3,4,5,6}中的变量i)
{
收益率i;
}
}
}

现在就把它放到我的博客上,非常方便。

虽然LINQ本身并没有这个功能,但框架本身有。。。您可以轻松地将自己的异步查询执行器滚动到30行左右。。。事实上,我只是为你准备了这个:)

EDIT:通过写这篇文章,我发现了他们为什么没有实现它。它无法处理匿名类型,因为它们的作用域是本地的。因此,您无法定义回调函数。这是一件非常重要的事情,因为很多linq到sql的东西都是在select子句中创建回调函数的。下面的任何一个建议都会遭受同样的命运,所以我仍然认为这一个是最容易使用的

编辑:唯一的解决方案是不使用匿名类型。您可以将回调声明为只接受IEnumerable(无类型args),并使用反射来访问字段(ICK!!)。另一种方法是将回调声明为“动态”。。。哦等待那还没有出来。:)这是如何使用dynamic的另一个不错的例子。有些人可能称之为虐待

将其放入实用程序库:

public static class AsynchronousQueryExecutor
{
    public static void Call<T>(IEnumerable<T> query, Action<IEnumerable<T>> callback, Action<Exception> errorCallback)
    {
        Func<IEnumerable<T>, IEnumerable<T>> func =
            new Func<IEnumerable<T>, IEnumerable<T>>(InnerEnumerate<T>);
        IEnumerable<T> result = null;
        IAsyncResult ar = func.BeginInvoke(
                            query,
                            new AsyncCallback(delegate(IAsyncResult arr)
                            {
                                try
                                {
                                    result = ((Func<IEnumerable<T>, IEnumerable<T>>)((AsyncResult)arr).AsyncDelegate).EndInvoke(arr);
                                }
                                catch (Exception ex)
                                {
                                    if (errorCallback != null)
                                    {
                                        errorCallback(ex);
                                    }
                                    return;
                                }
                                //errors from inside here are the callbacks problem
                                //I think it would be confusing to report them
                                callback(result);
                            }),
                            null);
    }
    private static IEnumerable<T> InnerEnumerate<T>(IEnumerable<T> query)
    {
        foreach (var item in query) //the method hangs here while the query executes
        {
            yield return item;
        }
    }
}
公共静态类AsynchronousQueryExecutor
{
公共静态void调用(IEnumerable查询、Action回调、Action errorCallback)
{
Func Func=
新函数(内部枚举);
IEnumerable结果=null;
IAsyncResult ar=func.BeginInvoke(
查询
新的异步回调(委托(IAsyncResult arr)
{
尝试
{
结果=((Func)((AsyncResult)arr.AsyncDelegate.EndInvoke(arr);
}
捕获(例外情况除外)