为什么VB中的lambda表达式与C#不同?

我刚刚遇到NHibernate中的一个错误,该错误恰好已经被提出: https : //nhibernate.jira.com/browse/NH-2763

我不确定这是否适用于枚举以外的任何其他内容,但是当使用VB中的Lambda时,它看起来与C#中的相同Lambda不同。

C#:

Where(x => x.Status == EmployeeStatus.Active) 

VB

 Where(Function(x) x.Status = EmployeeStatus.Active) 

就我所知,它们是一样的吗? (我的VB不是很好)

如果我在同一行代码上放置一个断点,那么上面的代码将被传入。 在C#中我得到:

C#版本

在VB版本传入的同一行,我得到:

VB版

这是我做错了吗? 结果是否相同,只是在C#/ VB之间显示不同?

编辑:好的,所以它们显示不同,但它们不能相同,因为NHibernate无法处理它。 NHibernate完全处理了C#版本,VB版本在抛出以下exception时解决:

例外

NHibernate StackTrace:

  at NHibernate.Impl.ExpressionProcessor.FindMemberExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 168 at NHibernate.Impl.ExpressionProcessor.ProcessSimpleExpression(Expression left, Expression right, ExpressionType nodeType) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 323 at NHibernate.Impl.ExpressionProcessor.ProcessSimpleExpression(BinaryExpression be) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 316 at NHibernate.Impl.ExpressionProcessor.ProcessBinaryExpression(BinaryExpression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 418 at NHibernate.Impl.ExpressionProcessor.ProcessExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 486 at NHibernate.Impl.ExpressionProcessor.ProcessExpression[T](Expression`1 expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 504 at NHibernate.Criterion.QueryOver`2.Add(Expression`1 expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Criterion\QueryOver.cs:line 635 at NHibernate.Criterion.QueryOver`2.NHibernate.IQueryOver.Where(Expression`1 expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Criterion\QueryOver.cs:line 686 at *removed*.EmployeeRepository.GetByEntityId(Int64 entityId, Expression`1 basicCriteria) in D:\*removed*\EmployeeRepository.cs:line 76 

那两者之间一定有什么不同?

编辑2:

对于乔纳森。 这是使用表达式的方法:

 public IEnumerable GetByEntityId(long entityId, Expression<Func> basicCriteria) { IEnumerable result; using (var tx = Session.BeginTransaction()) { var employeeQuery = Session.QueryOver() .Where(x => x.EntityId == entityId); if (basicCriteria != null) employeeQuery = employeeQuery.Where(basicCriteria); result = employeeQuery.List(); tx.Commit(); } return result; } 

你所看到的差异与lambdas无关; 它只是语言语义的差异。 VB正在向函数发出调用,默认情况下,如果整数溢出则抛出exception(因此名称的Checked部分)。

默认情况下,C#编译器不会发出“已检查”版本的函数,显然NHibernate是由C#用户开发的,因此它似乎无法识别“已检查”函数。

如果您转到项目的“编译”选项并单击“高级编译选项”,则可以选中“删除整数溢出检查”框,以便VB具有默认的C#行为,您不应再出现该错误:

对话框显示选项的屏幕截图

<>__DisplayClass的部分意味着编译器创建了一个闭包。 这意味着调试器中的表达式不是您展示的那个,而是类似的

 var status = EmployeeStatus.Active; Expression> expr = x => x.Status == status; 

但这不是NHibernate遇到问题的部分。 ConvertConvertChecked之间的区别是。 这是由C#和VB.NET之间的语义差异引起的:

在C#中,默认情况下,所有运行时计算都是未选中的,也就是说,不检查算术溢出。 您可以使用checked更改特定代码段的默认值。

在VB中,默认是检查计算,这会导致生成不同的lambda。 我敢肯定有办法在VB中改变它。

因此,以下C#代码创建与VB相同的lambda:

 checked { Expression> expr = x => x.Status == EmployeeStatus.Active; } 

编辑:如果您没有找到另一个选项,作为最后的手段,您可以使用Convert而不是ConvertChecked Convert VB.NET生成的表达式重写为表单:

 Class UncheckedVisitor Inherits ExpressionVisitor Protected Overrides Function VisitUnary ( _ node As UnaryExpression _ ) As Expression If node.NodeType = ExpressionType.ConvertChecked node = Expression.Convert(node.Operand, node.Type, node.Method) End If Return MyBase.VisitUnary(node) End Function End Class 

unchechedVisitor.Visit(expr)然后返回expr ,并将ConvertChecked所有实例替换为Convert

是的它只是显示不同。 你没有做错任何事。 VB内联方法有另一种语法和IDE集成