我正在构建一个LINQ表达式树,但它不会编译,因为据称局部变量$var1超出了范围:
变量''类型'System.Object'从范围''引用,但它没有定义
这是表达式树:
.Block() {
$var1;
.If ($n.Property1 == null) {
.Block() {
$var1 = null;
.Return #Label1 { }
}
} .Else {
.Default(System.Void)
};
$var1 = (System.Object)($n.Property1).Length;
.Label
.LabelTarget #Label1:;
$var1
}
Run Code Online (Sandbox Code Playgroud)
以下代码负责构建树.它是更大的东西的一部分,因此我不希望它的目的从这个例子中完全清楚.
MemberExpression sourceExpression = ...;
List<Expression> expressions = new List<Expression>();
LabelTarget returnTarget = Expression.Label();
ParameterExpression resultVariable = Expression.Variable(typeof(object));
expressions.Add(resultVariable);
expressions.Add(
Expression.IfThen(
Expression.Equal(sourceExpression, Expression.Constant(null)),
Expression.Block(
Expression.Assign(resultVariable, Expression.Constant(null)),
Expression.Return(returnTarget))));
expressions.Add(
Expression.Assign(
resultVariable,
Expression.Convert(sourceExpression, typeof(object))));
expressions.Add(Expression.Label(returnTarget));
expressions.Add(resultVariable);
Expression finalExpression = Expression.Block(expressions);
object result = Expression.Lambda<Func<object>>(finalExpression).Compile()();
Run Code Online (Sandbox Code Playgroud)
所以问题是:如何将局部变量放入范围,以便表达式成功编译?
LINQ表达树是否适当的树,如图,(有针对性或不指向,维基百科似乎不太一致)没有循环?以下C#表达式中表达式树的根是什么?
(string s) => s.Length
Run Code Online (Sandbox Code Playgroud)
表达式树看起来像这样," - >"表示可通过其他节点访问的节点的属性名称.
->Parameters[0]
Lambda---------Parameter(string s)
\ /
\->Body /->Expression
\ /
Member(Length)
Run Code Online (Sandbox Code Playgroud)
使用ExpressionVisitor访问LambdaExpression时,将访问ParameterExpression两次.有没有办法使用ExpressionVisitor访问LambdaExpression,以便所有节点只访问一次,并以特定的,众所周知的顺序(预订,有序,后订单等)?
那么,以下代码是自我解释的; 我想将两个表达式合并为一个使用And运算符.最后一行导致符文时间错误:
附加信息:从范围''引用的'System.String'类型的变量'y',但未定义
码:
Expression<Func<string, bool>> e1 = y => y.Length < 100;
Expression<Func<string, bool>> e2 = y => y.Length < 200;
var e3 = Expression.And(e1.Body, e2.Body);
var e4 = Expression.Lambda<Func<string, bool>>(e3, e1.Parameters.ToArray());
e4.Compile(); // <--- causes run-time error
Run Code Online (Sandbox Code Playgroud) 我有一个带有属性的简单类
class Foo
{
string Title { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我试图通过调用函数来简化数据绑定
BindToText(titleTextBox, ()=>foo.Title );
Run Code Online (Sandbox Code Playgroud)
这被宣称为
void BindToText<T>(Control control, Expression<Func<T>> property)
{
var mex = property.Body as MemberExpression;
string name = mex.Member.Name;
control.DataBindings.Add("Text", ??? , name);
}
Run Code Online (Sandbox Code Playgroud)
那么我应该???为我的Foo班级实例投入什么呢.如何foo从lambda表达式中获取对调用实例的引用?
编辑:
实例应该在某处,因为我可以调用property.Compile()并创建一个使用foo我的BindToText函数中的实例的委托.所以我的问题是,如果可以在不添加函数参数中实例的引用的情况下完成此操作.我呼吁Occum的Razor提供最简单的解决方案.
编辑2:
许多人没有注意到的是在我的函数内部访问实例时存在的闭包foo,如果我编译lambda.为什么编译器知道在哪里找到实例,我不知道?我坚持认为必须有一个答案,而不必通过额外的论证.
感谢VirtualBlackFox解决方案是这样的:
void BindText<T>(TextBoxBase text, Expression<Func<T>> property)
{
var mex = property.Body as MemberExpression;
string name = …Run Code Online (Sandbox Code Playgroud) 我正在使用LinqKit库,它允许动态组合表达式.
这是编写Entity Framewok数据访问层的纯粹幸福,因为可以选择重复使用和组合多个表达式,这样就可以实现可读和高效的代码.
请考虑以下代码:
private static readonly Expression<Func<Message, int, MessageView>> _selectMessageViewExpr =
( Message msg, int requestingUserId ) =>
new MessageView
{
MessageID = msg.ID,
RequestingUserID = requestingUserId,
Body = ( msg.RootMessage == null ) ? msg.Body : msg.RootMessage.Body,
Title = ( ( msg.RootMessage == null ) ? msg.Title : msg.RootMessage.Title ) ?? string.Empty
};
Run Code Online (Sandbox Code Playgroud)
我们声明了一个投射Message到的表达式MessageView(为了清楚起见,我删除了细节).
现在,数据访问代码可以使用此表达式来获取单个消息:
var query = CompiledQueryCache.Instance.GetCompiledQuery(
"GetMessageView",
() => CompiledQuery.Compile(
_getMessagesExpr
.Select( msg => _selectMessageViewExpr.Invoke( msg, userId ) ) …Run Code Online (Sandbox Code Playgroud) 您可能会认为这是一个错误报告,但是我很好奇我是否在这里非常错误,或者是否有来自Eric或Microsoft的其他人的解释.
现在,这是作为 Microsoft Connect上的错误发布的.
考虑以下课程:
class A
{
public object B {
set { }
}
}
Run Code Online (Sandbox Code Playgroud)
这里A.B是一个只写但其他方面很好的属性.
现在,想象一下我们在表达式中分配它:
Expression<Func<A>> expr =
() => new A {
B = new object { }
};
Run Code Online (Sandbox Code Playgroud)
此代码使C#编译器(3.5 .30729.4926和4.0 .30319.1)吐出
内部编译器错误(地址013E213F处的0xc0000005):可能的罪魁祸首是"BIND".
和崩溃.
但是,仅{ }使用构造函数(( ))替换对象初始化程序语法()就可以了.
using System;
using System.Linq.Expressions;
class Test {
public static void Main()
{
Expression<Func<A>> expr =
() => new …Run Code Online (Sandbox Code Playgroud) c# compiler-construction expression-trees writeonly compiler-bug
我需要使用模式工厂的想法将我的Person类实体中的实体属性Address与我的FactoryEntities类中的表达式linq相关联,看看这就是我拥有的和我想做的事情:
Address address = new Address();
address.Country = "Chile";
address.City = "Santiago";
address.ZipCode = "43532";
//Factory instance creation object
//This is idea
Person person = new FactoryEntity<Person>().AssociateWithEntity(p=>p.Address, address);
public class Person: Entity
{
public string Name{ get; set; }
public string LastName{ get; set; }
public Address Address{ get; set; }
}
public class Address: Entity
{
public string Country{ get; set; }
public string City{ get; set; }
public string ZipCode{ get; set; }
}
public class FactoryEntity<TEntity> where …Run Code Online (Sandbox Code Playgroud) 我想在执行之前重写LINQ表达式的某些部分.而且我在将重写器注入正确的位置时遇到了问题(实际上是这样).
查看实体框架源(在反射器中)它最终归结为IQueryProvider.ExecuteEF中的哪一个通过ObjectContext提供internal IQueryProvider Provider { get; }属性与表达式耦合.
所以我创建了一个包装器类(实现IQueryProvider),在调用Execute时执行Expression重写,然后将其传递给原始的Provider.
问题是,背后的领域Provider是private ObjectQueryProvider _queryProvider;.这ObjectQueryProvider 是一个内部密封类,这意味着不可能创建一个提供添加重写的子类.
因此,由于非常紧密耦合的ObjectContext,这种方法让我陷入了死胡同.
如何解决这个问题呢?我看错了方向吗?有没有办法让自己注意到这个ObjectQueryProvider?
更新:虽然提供的解决方案在您使用存储库模式"包装"ObjectContext时都能正常工作,但是允许直接使用ObjectContext生成的子类的解决方案将更可取.因此保持与Dynamic Data脚手架兼容.
为什么Func<>从Expression<Func<>>via .Compile()创建的文件比直接使用Func<>声明要慢得多?
我刚刚使用Func<IInterface, object>声明直接更改为Expression<Func<IInterface, object>>在我正在处理的应用程序中创建的一个,我注意到性能下降了.
我刚做了一点测试,Func<>从一个Expression创建的"几乎"是Func<>直接声明的时间的两倍.
在我的机器上,Direct Func<>大约需要7.5秒,Expression<Func<>>大约需要12.6秒.
这是我使用的测试代码(运行Net 4.0)
// Direct
Func<int, Foo> test1 = x => new Foo(x * 2);
int counter1 = 0;
Stopwatch s1 = new Stopwatch();
s1.Start();
for (int i = 0; i < 300000000; i++)
{
counter1 += test1(i).Value;
}
s1.Stop();
var result1 = s1.Elapsed;
// Expression . Compile()
Expression<Func<int, Foo>> expression = x => new Foo(x …Run Code Online (Sandbox Code Playgroud) 注意:我知道使用动态linq创建它很简单,但我想学习.
我想创建一个"找到"的lambda:Name = David AND Age = 10.
class Person
{
public int Age { get; set; }
public string Name { get; set; }
}
var lambda = LabmdaExpression<Person>("Name", "David", "Age", 10);
static Expression<Func<T, bool>> LabmdaExpression<T>(string property1, string value1, string property2, int value2)
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(Person), "o");
MemberExpression memberExpression1 = Expression.PropertyOrField(parameterExpression, property1);
MemberExpression memberExpression2 = Expression.PropertyOrField(parameterExpression, property2);
ConstantExpression valueExpression1 = Expression.Constant(value1, typeof(string));
ConstantExpression valueExpression2 = Expression.Constant(value2, typeof(int));
BinaryExpression binaryExpression1 = Expression.Equal(memberExpression1, valueExpression1);
BinaryExpression binaryExpression2 = Expression.Equal(memberExpression2, valueExpression2); …Run Code Online (Sandbox Code Playgroud) c# ×10
expression-trees ×10
linq ×5
lambda ×4
.net ×1
.net-3.5 ×1
closures ×1
compiler-bug ×1
data-binding ×1
delegates ×1
expression ×1
func ×1
linqkit ×1
writeonly ×1