【问题标题】:Why do lambda expressions in VB differ from C#?为什么 VB 中的 lambda 表达式与 C# 不同?
【发布时间】:2011-07-19 06:11:36
【问题描述】:

我刚刚在 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# 中我得到:

在传入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

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

编辑 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;
}

【问题讨论】:

  • 哇,VB.net 对 lambdas 的调试真是太棒了!
  • @Mehrdad / @fantasticfix - 我已经更新了我的问题以包含异常。 VB 和 C# 版本之间肯定有区别。
  • 对不起... bool >> basicCriteria 是做什么的?
  • @Jonathan - 添加了使用“basicCriteria”的方法。无非是提供对结果的次要过滤。在这种情况下,按状态过滤员工。
  • @Petr,和 C# 一样。

标签: c# vb.net lambda


【解决方案1】:

您看到的差异与 lambda 无关;这只是语言语义上的差异。 VB 发出对函数的调用,如果整数溢出,默认情况下会抛出异常(因此名称中包含 Checked 部分)。

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

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

【讨论】:

  • 你先生,是个传奇。 :D 未选中,它工作得很好。不幸的是,我不喜欢让它关闭,这是一个 10 年的代码库。所以必须写一些方法重载:(
  • @Phill:你知道你有没有最新版本的NHibernate吗?您可能遇到了一个已经修复的错误。
  • 我正在使用 3.1,Fluent NHibernate 网站尚未更新它的 3.2 版本,我不想编译自己的构建。但是当 Fluent 的下一个版本发布时,我会更新并重新测试。明天我到办公室时会测试 svick 的代码。
【解决方案2】:

带有&lt;&gt;__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 而不是ConvertChecked 将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

【讨论】:

  • 感谢您的解释。当我读到 Gabe 的回答时,我意识到发生了什么。 VB 没有相当于 C# 的unchecked 是吗?我快速谷歌了一下,但这一切都导致取消选中项目设置。
  • @Phill,不知道,我实际上并没有使用 VB.NET。
  • 哈哈,没问题。我做了一点 VB,因为现有的应用程序是在 VB 中的。所有的新东西都在 C# 中。所以问题是 VB 网站,C# 其他一切。 :(
  • 干杯,我明天一进办公室就试试。感谢您的帮助!
  • :( 它仅在 .NET 4.0 中受支持,不幸的是我被困在 3.5 上。
【解决方案3】:

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

【讨论】:

  • 不同的 IDE 集成肯定不是生成表达式存在差异的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
相关资源
最近更新 更多