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

Phi*_*ill 11 c# vb.net lambda

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

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

C#:

Where(x => x.Status == EmployeeStatus.Active)
Run Code Online (Sandbox Code Playgroud)

VB

Where(Function(x) x.Status = EmployeeStatus.Active)
Run Code Online (Sandbox Code Playgroud)

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

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

C#版本

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

VB版

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

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

例外

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
Run Code Online (Sandbox Code Playgroud)

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

编辑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;
}
Run Code Online (Sandbox Code Playgroud)

Gab*_*abe 10

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

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

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

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


svi*_*ick 5

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

var status = EmployeeStatus.Active;
Expression<Func<Employee, bool>> expr = x => x.Status == status;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

checked
{
    Expression<Func<Employee, bool>> expr = x => x.Status == EmployeeStatus.Active;
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果你没有找到另一个选项,作为最后的手段,你可以使用Convert而不是代码重写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
Run Code Online (Sandbox Code Playgroud)

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