views:

232

answers:

1

Hi!

Given the lambda expression below where Province type contains a public property "byte CountryId" and Country type which contains a public property "byte Id".

Expression<Func<Province, bool>> exp = p => p.CountryId == country.Id;

The Expression is later used by NHibernate Linq provider and threw an exception. When I inspected the expression variable exp, I found out that both sides of the equality operator were converted to Int32.

{p => (Convert(p.CountryId) = Convert(value
(AddressToGo.Business.Default.AddressComponents+<>c__DisplayClass0).country.Id))}

I can't understand why the equality operator for two byte values need those values to be converted to Int32 beforehand. I have written the expression directly wihout letting the compiler do it for me. The following expression is converted by NHibernate Linq provider just fine.

ParameterExpression prm = Expression.Parameter(typeof(Province), "p");
  Expression<Func<Province, bool>> exp =
      Expression.Lambda<Func<Province, bool>>
      (
        Expression.Equal
        (
          Expression.MakeMemberAccess(prm, typeof(Province).GetProperty("CountryId")),
          Expression.Constant(country.Id, typeof(byte))
        ),
        prm
      );

So, there must be a reason why the compiler outputs the expression with type conversion. Any ideas?

+3  A: 

This is per the specification. Quoting from §4.1.5:

C# supports nine integral types: sbyte, byte, short, ushort, int, uint, long, ulong, and char. [...]

The integral-type unary and binary operators always operate with signed 32-bit precision, unsigned 32-bit precision, signed 64-bit precision, or unsigned 64-bit precision:

[...]

For the binary +, , *, /, %, &, ^, |, ==, !=, >, <, >=, and <= operators, the operands are converted to type T, where T is the first of int, uint, long, and ulong that can fully represent all possible values of both operands. The operation is then performed using the precision of type T, and the type of the result is T (or bool for the relational operators). It is not permitted for one operand to be of type long and the other to be of type ulong with the binary operators.

Thus, for

byte b1;
byte b2;
bool b = (b1 == b2);

the operands b1 and b2 are promoted to int before == is invoked.

Jason
Thank you for the answer. This explains the compiler behaviour of converting the byte type values to int32. However, it still doesn't make sense. Since the lambda expression is converted into an expression, not a compiled delegate, it must still be an expression tree which can later be defined in any language, including C#, HQL etc. So I think it must be free of any language specific implementations. NHibernate Linq provider wouldn't need the promotion of variable types before operating on them. Is the lambda expression compiled before being converted to an expression tree?
HaDeS