我刚刚遇到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;
}
答案 0 :(得分:10)
你所看到的差异与lambdas无关;它只是语言语义的差异。 VB正在向函数发出调用,默认情况下,如果整数溢出(因此名称的Checked
部分),则抛出异常。
默认情况下,C#编译器不会发出“已检查”版本的函数,显然NHibernate是由C#用户开发的,因此它似乎无法识别“已检查”函数。
如果您转到项目的“编译”选项并单击“高级编译选项”,则可以选中“删除整数溢出检查”框,以便VB具有默认的C#行为,您不应再出现该错误:< / p>
答案 1 :(得分:5)
<>__DisplayClass
的部分表示编译器创建了一个闭包。这意味着调试器中的表达式不是您显示的表达式,而是类似
var status = EmployeeStatus.Active;
Expression<Func<Employee, bool>> expr = x => x.Status == status;
但这不是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;
}
编辑:如果您没有找到其他选项,作为最后的手段,您可以使用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集成