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

时间:2011-07-19 06:11:37

标签: c# vb.net lambda

我刚刚遇到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# version

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

VB version

这是我做错了吗?结果是否相同,只是在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<TRoot,TSubType>.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<Employee> GetByEntityId(long entityId, Expression<Func<Employee, bool>> basicCriteria)
{
    IEnumerable<Employee> result;

    using (var tx = Session.BeginTransaction())
    {
        var employeeQuery = Session.QueryOver<Employee>()
                                    .Where(x => x.EntityId == entityId);

        if (basicCriteria != null)
            employeeQuery = employeeQuery.Where(basicCriteria);

        result = employeeQuery.List();

        tx.Commit();
    }

    return result;
}

3 个答案:

答案 0 :(得分:10)

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

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

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

Screenshot of dialog showing option

答案 1 :(得分:5)

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

的表达式
var status = EmployeeStatus.Active;
Expression<Func<Employee, bool>> expr = x => x.Status == status;

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

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

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

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

checked
{
    Expression<Func<Employee, bool>> expr = x => x.Status == EmployeeStatus.Active;
}

编辑:如果您没有找到其他选项,作为最后的手段,您可以使用Convert而不是{{1}将VB.NET生成的表达式重写为表单}:

ConvertChecked

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

答案 2 :(得分:2)

是的,它只是显示不同。 你什么都不做错。 VB内联方法有另一种语法和IDE集成