Lambda表达式编译

6

考虑以下Lambda表达式,其中Province类型包含一个公共属性“byte CountryId”,而Country类型包含一个公共属性“byte Id”。

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

后来NHibernate Linq提供程序使用了该表达式并抛出了异常。当我检查表达式变量exp时,发现等号运算符的两侧都被转换为Int32。

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

我不明白为什么两个字节值的等号运算符需要将这些值事先转换为Int32。 我已经直接编写了表达式,而没有让编译器为我执行它。 NHibernate Linq提供程序可以很好地转换以下表达式。

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
      );

因此,编译器输出带有类型转换的表达式一定有其原因。你有什么想法吗?

1个回答

6
这符合规范。引用自§4.1.5:
C#支持九种整数类型:sbytebyteshortushortintuintlongulongchar。[...]
整数类型的一元和二元运算符始终使用带有32位有符号精度、32位无符号精度、64位有符号精度或64位无符号精度:
[...]
对于二元运算符+-*/%&^|==!=><>=<=,操作数将转换为类型T,其中T是int、uint、long和ulong中能够完全表示两个操作数的所有可能值的第一个类型。然后使用类型T的精度执行操作,结果的类型为T(或关系运算符的bool类型)。不允许一个操作数为long类型,另一个操作数为ulong类型。
因此,对于
byte b1;
byte b2;
bool b = (b1 == b2);

b1b2这两个操作数在执行==操作之前会被提升为int类型。


5
感谢你的回答。这解释了编译器将byte类型值转换为int32的行为。然而,仍然不太合理。由于lambda表达式被转换为表达式而不是已编译的委托,它必须仍然是一个表达式树,可以在任何语言中定义,包括C#、HQL等。因此,我认为它必须不包含任何特定于语言的实现。NHibernate Linq提供程序在对变量进行操作之前不需要类型提升。lambda表达式是否在转换为表达式树之前进行编译? - user251516

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接