I just came across a bug in NHibernate which happens to already be raised: https://nhibernate.jira.com/browse/NH-2763
I'm not sure if this applies to anything else other than enums but when using a Lambda from VB, it looks different to the same Lambda from C#.
C#:
Where(x => x.Status == EmployeeStatus.Active)
VB
Where(Function(x) x.Status = EmployeeStatus.Active)
They are the same as far as I'm aware? (My VB isn't great)
If I put a break point on the same line of code, where the above code is passed into. In C# I get:
On the same line when VB version is passed in, I get:
Is this something I'm doing wrong? Is the result's the same, just displayed different between C#/VB?
Edit: Ok so they are displayed different, but they can't be the same because NHibernate cannot handle it. The C# version is handled perfectly fine by NHibernate, the VB version resolves in the following exception being thrown:
The 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
So something must be different between the two?
Edit 2:
For Jonathan. This is the method where the expression is used:
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;
}
Yes its just displayed different. You do nothing wrong. The VB inline methods have another syntax and also IDE integration
The part with
<>__DisplayClass
means the compiler created a closure. That means the expression in the debugger is not the one you showed but rather something likeBut this is not the part NHibernate is having problems with. The difference between
Convert
andConvertChecked
is. And that is caused by a difference in semantics between C# and VB.NET:In C#, by default, all runtime computations are unchecked, that is, they are not checked for arithmetic overflows. You can change the default for a particular piece of code using
checked
.In VB, the default is to have computations checked, which results in different generated lambda. I'm sure there are ways to change this in VB too.
So the following C# code creates the same lambda as your VB:
EDIT: If you don't find another option, as a last resort, you could rewrite the expression VB.NET generates into a form using
Convert
instead ofConvertChecked
:unchechedVisitor.Visit(expr)
then returnsexpr
with all instances ofConvertChecked
replaced withConvert
.The difference you are seeing has nothing to do with lambdas; it is simply a difference in the semantics of the languages. VB is emitting calls to functions that by default throw exceptions if an integer overflows (hence the
Checked
part of the name).By default the C# compiler does not emit the "checked" version of functions, and apparently NHibernate is developed by C# users, so it doesn't seem to recognize the "checked" functions.
If you go to the Compile options for your project and click on Advanced Compile Options, you can check the "Remove integer overflow checks" box so that VB has the default C# behavior and you shouldn't get that error anymore: