Why are lambda expressions in VB different from C #?

I just stumbled upon an error in NHibernate, which may already have been raised: https://nhibernate.jira.com/browse/NH-2763

I'm not sure if this applies to anything but the others, but when using Lambda from VB it looks different than Lambda from C #.

FROM#:

Where(x => x.Status == EmployeeStatus.Active) 

B. B.

 Where(Function(x) x.Status = EmployeeStatus.Active) 

Are they the same as far as I know? (My VB is not great)

If I put a breakpoint on the same line of code that the above code is passed to. In C #, I get:

C # version

On the same line when the VB version is being transferred, I get:

Vb version

Am I doing something wrong? Is the result the same just displayed between C # / VB?

Edit: Okay, so they appear different, but they cannot be the same because NHibernate cannot handle this. The C # version is handled nicely by NHibernate, the VB version is allowed with the following exception:

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 

So, should something be different between the two?

Edit 2:

For Jonathan. This is a method that uses an expression:

 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; } 
+11
c # lambda
Jul 19 '11 at 6:11
source share
3 answers

The difference you see has nothing to do with lambdas; it's just the difference in the semantics of languages. VB emits function calls that, by default, throw exceptions if the integer overflows (hence the Checked part).

By default, the C # compiler does not allocate a β€œverified” version of functions, and NHibernate seems to be developed by C # users, so it does not seem to recognize β€œtested” functions.

If you go to the "Compilation" options for your project and click "Advanced compilation options", you can check the "Exclude integer overflow check" check box so that VB has C # default behavior and you should no longer get this error:

Screenshot of dialog showing option

+10
Jul 19 '11 at 7:00
source share

The part with <>__DisplayClass means that the compiler created the closure. This means that the expression in the debugger is not the one you showed, but something like

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

But this is not the part that NHibernate has problems with. The difference between Convert and ConvertChecked is equal. And this is caused by the difference in semantics between C # and VB.NET:

In C #, by default, all calculations are not checked at runtime, that is, they are not checked for arithmetic overflows. You can change the default value for a specific piece of code using checked .

In VB, the calculation is checked by default, which leads to different generated lambda. I am sure there are ways to change this on VB as well.

So, the following C # code creates the same lambda as your VB:

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

EDIT: If you don't find another option, as a last resort, you can rewrite the expression that VB.NET generates in the form using Convert instead of 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) then returns expr , where all ConvertChecked instances ConvertChecked replaced by Convert .

+5
Jul 19 '11 at 7:15
source share

Yes, it just shows up to others. You are not doing anything wrong. VB inline methods have a different syntax as well as IDE integration

+2
Jul 19 '11 at 6:14
source share



All Articles