我想构建一个自定义LINQ提供程序.主要用于学习目的,但它可能在将来有用.我听说这不是一件简单的事情,但......
编写自定义LINQ提供程序的一些好教程在哪里?
我一直在学习IQueryable和延迟加载/延迟执行查询.
是否可以通过WCF公开此功能?我想暴露LINQ到SQL服务,返回一个IQueryable,我可以然后在客户端执行额外的查询,最后使用.ToList的execute().OData格式在这种情况下是否适用?
如果可能的话,究竟是什么技术术语,什么是一些很好的教程,我可以遵循?谢谢.
linq wcf iqueryable custom-linq-providers deferred-execution
我已经阅读了这个答案并从中理解了它突出显示的具体情况,即当你在另一个lambda中有一个lambda并且你不想意外地让内部lambda也用外部lambda编译时.编译外部时,您希望内部lambda表达式保留为表达式树.在那里,是的,引用内部lambda表达式是有道理的.
但我相信这就是它.是否还有其他用例来引用lambda表达式?
如果没有,为什么所有LINQ运算符,即IQueryable<T>在Queryable类中声明的扩展引用谓词或lambda作为参数,当它们将信息打包在MethodCallExpression.
我尝试了一个例子(以及过去几天的其他一些例子),在这种情况下引用lambda似乎没有任何意义.
这是一个方法调用表达式,该方法需要一个lambda表达式(而不是委托实例)作为唯一参数.
然后我MethodCallExpression通过将其包装在lambda中来编译它.
但是,这也不会编译内部LambdaExpression(GimmeExpression方法的参数).它将内部lambda表达式保留为表达式树,并且不创建它的委托实例.
事实上,它没有引用它很好.
如果我引用该参数,它会中断并给出一个错误,表明我向该GimmeExpression方法传递了错误的参数类型.
这是怎么回事?这引用的内容是什么?
private static void TestMethodCallCompilation()
{
var methodInfo = typeof(Program).GetMethod("GimmeExpression",
BindingFlags.NonPublic | BindingFlags.Static);
var lambdaExpression = Expression.Lambda<Func<bool>>(Expression.Constant(true));
var methodCallExpression = Expression.Call(null, methodInfo, lambdaExpression);
var wrapperLambda = Expression.Lambda(methodCallExpression);
wrapperLambda.Compile().DynamicInvoke();
}
private static void GimmeExpression(Expression<Func<bool>> exp)
{
Console.WriteLine(exp.GetType());
Console.WriteLine("Compiling and executing expression...");
Console.WriteLine(exp.Compile().Invoke());
}
Run Code Online (Sandbox Code Playgroud) 我已经实现了简单的IQueryable和IQueryProvider在LINQ表达式树上收集统计数据的类.这部分工作正常.接下来,我想将表达式树传递给默认的LINQ-to-Objects提供程序进行评估,因为我不需要以任何不同的方式执行它.换句话说,我希望我的提供者收集统计信息作为副作用,将查询传递给默认的LINQ实现.
但是,我很难获得默认提供程序的句柄.我以为我可以简单地保存对原始IEnumerable集合的引用,然后返回默认提供程序(来自我的自定义IQueryable),如:
IQueryProvider IQueryable.Provider
{
get { return _my_provider.OriginalIEnum().AsQueryable().Provider; }
}
Run Code Online (Sandbox Code Playgroud)
但这不能正常工作.代码最终会抛出一个StackOverflowException.我认为正在发生的事情(从调试模式中的单步执行中收集)是LINQ运行时从上面的方法中获取提供程序,然后从我的自定义中获取表达式树IQueryable,然后它注意到顶级表达式是我的习惯IQueryable.所以它重新开始这个过程,试图找到合适的提供者.它会无休止地执行此操作,直到发生堆栈溢出.
现在,我唯一能想到的就是想出另一个访问者,它生成了另一个IQueryable删除了自定义节点的表达式树,以便LINQ运行时调用默认的提供者.这是相当多的工作,因为我需要访问每个叶子以确保没有嵌套Call表达式IQueryable再次调用我的自定义.有更简单的方法吗?
谢谢您的帮助.
我正在尝试按照创建IQueryable LINQ提供程序的说明进行操作,但是当我实现ExpressionVisitor按照指示继承的类时,我被告知ExpressionVisitor由于其保护级别而无法访问.我错过了一些非常基本的东西吗?
expression iqueryable custom-linq-providers expressionvisitor
我想验证我的假设,即LINQ Expression API没有任何方法可以让我们创建一个表示局部变量创建的表达式.
换句话说,您无法创建表达式来表示:
int local;
Run Code Online (Sandbox Code Playgroud)
因为那是一个变量声明语句,并且API不支持语句lambdas.lambda表达式(由LINQ表达式API(而不是委托实例)表示)可以使用的唯一状态是它接收的参数以及它通过闭包接收的捕获变量.
我的假设(基于几个月的LINQ Expression API实践)是否正确?
从文档及其名称暗示,可以推断对于可以进一步分解为更小的表达式的所有表达式,该属性的值CanReduce必须设置为 true,反之亦然。
但经过仔细观察,这个推论似乎并不在所有情况下都成立。以 为例LambdaExpression,它肯定是一个复合单元。但是LambdaExpression直接从Expression类派生的类不会覆盖该CanReduce属性。该类将属性Expression定义CanReduce为 virtual 并具有返回 的实现false,因此意味着 lambda 表达式不可进一步简化,但事实并非如此。
那么这个属性的真正意义是什么?