c# 表达式上的奇怪类型转换

Strange type conversion on c# Expressions

来个简单的class

class User
{
   public byte IdByte { get; set; }
}

所以当我写这样的表达式时:


Expression<Func<User, bool>> expression1 = x => x.IdByte == 3;

Expression<Func<User, bool>> expression2 = x => x.IdByte == (byte)3;

byte b = 3;
Expression<Func<User, bool>> expression3 = x => x.IdByte == b;

Expression<Func<User, bool>> expression4 = x => x.IdByte == byte.MaxValue;

并观察表达式调试视图,我看到还有一个类型转换为 System.Int32 类型:

//expression1  ------>  x => (Convert(x.IdByte, Int32) == 3)
//expression2  ------>  x => (Convert(x.IdByte, Int32) == 3)
//expression3  ------>  x => (Convert(x.IdByte, Int32) == Convert(value(....c__DisplayClass1_0).b, Int32))
//expression4  ------>  x => (Convert(x.IdByte, Int32) == 255)

在第一个和第二个表达式中,将右侧 - 3 转换为 byte 比将左侧转换为 int 更合理。
在其余情况下,左侧和右侧是字节
我的问题是为什么应用这些转换?

让我们检查一下 the spec:

Integer comparison operators

The predefined integer comparison operators are:

bool operator ==(int x, int y);
bool operator ==(uint x, uint y);
bool operator ==(long x, long y);
bool operator ==(ulong x, ulong y);

bool operator !=(int x, int y);
bool operator !=(uint x, uint y);
bool operator !=(long x, long y);
bool operator !=(ulong x, ulong y);

bool operator <(int x, int y);
bool operator <(uint x, uint y);
bool operator <(long x, long y);
bool operator <(ulong x, ulong y);

bool operator >(int x, int y);
bool operator >(uint x, uint y);
bool operator >(long x, long y);
bool operator >(ulong x, ulong y);

bool operator <=(int x, int y);
bool operator <=(uint x, uint y);
bool operator <=(long x, long y);
bool operator <=(ulong x, ulong y);

bool operator >=(int x, int y);
bool operator >=(uint x, uint y);
bool operator >=(long x, long y);
bool operator >=(ulong x, ulong y);

Each of these operators compares the numeric values of the two integer operands and returns a bool value that indicates whether the particular relation is true or false.

如您所见,我们实际上并没有比较两个 bytes 或两个 sbyteschars、[=18= 的 == 运算符], 或 ushorts.

但是,存在从这些类型到 int 的隐式转换,因此编译器将这些转换应用于双方,并使用 bool ==(int x, int y).

如果你写:

byte val = 3;
bool b = val == (byte)4;

编译器会有效地将其转换为:

byte val = 3;
bool b = (int)val == (int)(byte)4;

(int)(byte)4 转换当然是完全没有必要的:编译器只会将其转换为整数文字。

byte val = 3;
bool b = (int)val == 4;

以 canton7 的答案为基础。

为什么 bytes(和其他类型)特别转换为整数的原因是 语言互操作性 通过确保默认算术行为将在所有实现上产生相同的结果。

出于特定原因,我们必须参考控制 如何 运行时和编译器应如何处理类型的公共语言基础设施标准 (ECMA-335),无论是在评估中或验证堆栈。

ECMA-335 §III.1.1

While the [Common Type System] defines a rich type system and the [Common Language Specification] specifies a subset that can be used for language interoperability, the [Common Language Infrastructure] itself deals with a much simpler set of types.

ECMA-335 §III.1.1.1

The [Common Language Infrastructure] only operates on the numeric types int32 (4-byte signed integers), int64 (8-byte signed integers), native int (native-size integers), and F (native-size floating-point numbers).

ECMA-335 §III.1.1.1.2 的注释

Short (i.e., 1- and 2-byte) integers are loaded as 4-byte numbers on all architectures and these 4-byte numbers are always tracked as distinct from 8-byte numbers. This helps portability of code by ensuring that the default arithmetic behavior will have identical results on all implementations.