我有以下情况:
我尝试用我能找到的答案来解决表达式,但我所取得的最好成绩是IEnumerable,这是不可接受的,因为我需要IQueriable来过滤它。我来回搜索,但我找到的唯一可行的变体是DynamicSQL here,但我不允许使用它。
非常感谢任何想法。
更新:作为一个例子,我有两个由fk连接的随机表,所以它只是一个常规连接,如from t1 in Table1 join t2 in Table2 on t1.field1 = t2.field2
。我需要的是能够将select表达式传递给此连接,基于包含我想要选择的列的字符串集合构建,例如,如果我有{"t1.field1", "t1.field2", "t2.field3"}
,则连接应该看起来像{{1} }。
答案 0 :(得分:0)
从列列表创建实例的问题在于,由于.NET是类型安全的,因此您需要一个可以实例化的类型。当您使用匿名类(即没有类名的new
关键字)时,编译器将为您创建一个类。它是匿名的,但在编译时它仍然存在 (你可以在你选择的反编译器中检查它)。
如果你想在运行时真正完全动态 ,你必须在执行时动态创建和编译你的类。为此,您可能需要查看System.CodeDom
和System.Reflection.Emit
命名空间,它们都包含允许您在运行时动态创建类型的类。然而,这将是一项非常艰巨的任务,它怀疑值得您的时间。然后你想访问这些对象中的数据,所以你可能不得不去找dynamic
个变量。
更可行的是在编译时创建一个常规类并在LINQ查询中实例化它。此类将包含您可以设置的所有可能的属性。实例化它时,您不必填写所有字段。
一旦有了类,就可以动态创建将实例化它的表达式。这就是System.Linq.Expressions
命名空间中的类的用途。 Expression
类包含允许您创建所需表达式树的工厂方法。
要创建表达式树,首先必须分解要建模的表达式。 Join
的Yor表达式看起来与此类似(假设您的容器类名为DataContainer
):
(t1, t2) => new DataContainer {
Value1 = t1.field1,
Value2 = t1.field2,
Value3 = t2.field3
}
此表达式必须根据其优先级在其各个部分中拆分:
=>
LambdaExpression
:Expression.Lambda
启动的lambda表达式
t1
和t2
:ParameterExpression
,使用Expression.Parameter
new DataContainer
:NewExpression
,使用Expression.New
=
创建的初始化块内的分配:BinaryExpression
,使用Expression.Assign
MemberExpression
,使用Expression.Property
.field1
MemberExpression
:Expression.Property
解除引用的属性
t1
创建的参数访问ParameterExpression
:Expression.Parameter
(但您正在重复使用为lambda表达式创建的参数表达式)正如您所看到的,与仅写下表达式(或使用Dynamic LINQ)相比,这非常繁琐。我将用子表达式t1.field1
:
此时您将为lambda的左侧创建t1
参数:
ParameterExpression t1Param = Expression.Parameter(typeof(Table1), "t1");
您重复使用的属性访问权限:
MemberExpression t1field1Property = Expression.Property(t1Param, "field1");
您在创建作业时使用的表达式,您将与实例化表达式中的其他作业一起使用,该表达式将用于lamdba表达式的右侧,以及其他所需的表达式。您也可以将其写为单个树(除了要重用的参数表达式之外)。
快乐的编码!