C# 确定MemberExpressions目标的范围
这里有没有人有编写自定义Linq提供程序的经验 我要做的是告诉您,作为业务对象属性的MemberExpression是应该包含在SQL中,还是应该被视为常量,因为它来自恰好是业务对象的局部变量 例如,如果您有:C# 确定MemberExpressions目标的范围,c#,.net,linq,expression-trees,custom-linq-providers,C#,.net,Linq,Expression Trees,Custom Linq Providers,这里有没有人有编写自定义Linq提供程序的经验 我要做的是告诉您,作为业务对象属性的MemberExpression是应该包含在SQL中,还是应该被视为常量,因为它来自恰好是业务对象的局部变量 例如,如果您有: Customer c = LoadCustomerFromDatabase(); var orders = from o in db.Orders() where o.CustomerID == c.CustomerID select o; 目前,我的查询翻译器将尝试从订单o执行SE
Customer c = LoadCustomerFromDatabase();
var orders = from o in db.Orders() where o.CustomerID == c.CustomerID select o;
目前,我的查询翻译器将尝试从订单o执行SELECT*,其中o.CustomerID=c.CustomerID
,这当然不起作用
我想做的是检查c.CustomerID
上的MemberExpression,并尝试确定它是一个局部变量,还是只是用作Linq表达式的一部分
我已经设法把它作为查询的第二步,查找SQL Server无法绑定的字段,并注入它们的值,但如果可能的话,我希望所有这些都同时发生。我尝试查看表达式
Type
属性和IsAutoClass
,但这只是一个猜测,因为它包含单词Auto。它不起作用:)嗯,我不知道你是否可以把它简化为一个过程,但是你可以得到关于成员的信息,如果它与你声明为查询一部分的另一个变量(在本例中为“o”)一致,你就用它来生成你的查询
否则,您将假定它是一个常量,然后插入该值
不幸的是,由于在查询中可以在多个位置使用from语句(除了let语句),因此似乎不能一次完成,因为您需要事先了解所有查询变量。好的,在进行一些快速统计分析(即手动比较各个属性)后,DeclaringType,当Lambda参数不在范围“fires”中时,ReflectedType和Namespace是无效的
因此,除非有人提出更好的答案,否则这可能就是我要说的全部。在Where表达式中,您看到的是
表达式
——这意味着最外层的lambda应该有一个参数表达式
,类型为T
如果比较与行相关,则它将(作为祖先)具有此参数表达式
;如果它是局部变量,则它将(作为祖先)具有常量表达式
——但是,编译器将生成此常量表达式的类型,以处理表达式中使用的所有捕获变量
像这样:
using System;
using System.Linq.Expressions;
class Foo
{
public string Name { get; set; }
static void Main()
{
var exp = (LambdaExpression) GetExpression();
WalkTree(0, exp.Body, exp.Parameters[0]);
}
static void WriteLine(int offset, string message)
{
Console.WriteLine(new string('>',offset) + message);
}
static void WalkTree(int offset, Expression current,
ParameterExpression param)
{
WriteLine(offset, "Node: " + current.NodeType.ToString());
switch (current.NodeType)
{
case ExpressionType.Constant:
WriteLine(offset, "Constant (non-db)"
+ current.Type.FullName);
break;
case ExpressionType.Parameter:
if (!ReferenceEquals(param, current))
{
throw new InvalidOperationException(
"Unexpected parameter: " + param.Name);
}
WriteLine(offset, "db row: " + param.Name);
break;
case ExpressionType.Equal:
BinaryExpression be = (BinaryExpression)current;
WriteLine(offset, "Left:");
WalkTree(offset + 1, be.Left, param);
WriteLine(offset, "Right:");
WalkTree(offset + 1, be.Right, param);
break;
case ExpressionType.MemberAccess:
MemberExpression me = (MemberExpression)current;
WriteLine(offset, "Member: " + me.Member.Name);
WalkTree(offset + 1, me.Expression, param);
break;
default:
throw new NotSupportedException(
current.NodeType.ToString());
}
}
static Expression<Func<Foo, bool>> GetExpression()
{
Foo foo = new Foo { Name = "abc" };
return row => row.Name == foo.Name;
}
}
使用系统;
使用System.Linq.Expressions;
福班
{
公共字符串名称{get;set;}
静态void Main()
{
var exp=(LambdaExpression)GetExpression();
WalkTree(0,exp.Body,exp.Parameters[0]);
}
静态void WriteLine(整数偏移量,字符串消息)
{
Console.WriteLine(新字符串('>',偏移量)+消息);
}
静态void WalkTree(整数偏移,表达式当前,
参数expression param)
{
WriteLine(偏移量,“节点:+current.NodeType.ToString());
开关(当前.节点类型)
{
大小写表达式类型。常量:
写线(偏移量,“常数(非db)”
+当前.Type.FullName);
打破
大小写表达式类型。参数:
如果(!ReferenceEquals(参数,当前))
{
抛出新的InvalidOperationException(
“意外参数:”+参数名称);
}
写入线(偏移量,“数据库行:”+参数名称);
打破
大小写表达式类型。相等:
BinaryExpression be=(BinaryExpression)当前值;
写线(偏移量,左:);
WalkTree(偏移量+1,向左,参数);
写线(偏移量,右:);
WalkTree(偏移量+1,右侧,参数);
打破
case ExpressionType.MemberAccess:
MemberExpression me=(MemberExpression)当前值;
WriteLine(抵销,“成员:+me.Member.Name”);
WalkTree(偏移量+1,me.Expression,参数);
打破
违约:
抛出新的NotSupportedException(
current.NodeType.ToString());
}
}
静态表达式GetExpression()
{
Foo Foo=新Foo{Name=“abc”};
返回row=>row.Name==foo.Name;
}
}