Binary Shift Differences between VB.NET and C#

2020-02-26 07:19发布

I just found an interesting problem between translating some data:

VB.NET: CByte(4) << 8 Returns 4

But C#: (byte)4 << 8 Returns 1024

Namely, why does VB.NET: (CByte(4) << 8).GetType() return type {Name = "Byte" FullName = "System.Byte"}

Yet C#: ((byte)4 << 8).GetType() returns type {Name = "Int32" FullName = "System.Int32"}

Is there a reason why these two treat the binary shift the same? Following from that, is there any way to make the C# bit shift perform the same as VB.NET (to make VB.NET perform like C# you just do CInt(_____) << 8)?

3条回答
地球回转人心会变
2楼-- · 2020-02-26 07:58

Chris already nailed it, vb.net has defined shift operators for the Byte and Short types, C# does not. The C# spec is very similar to C and also a good match for the MSIL definitions for OpCodes.Shl, Shr and Shr_Un, they only accept int32, int64 and intptr operands. Accordingly, any byte or short sized operands are first converted to int32 with their implicit conversion.

That's a limitation that the vb.net compiler has to work with, it needs to generate extra code to make the byte and short specific versions of the operators work. The byte operator is implemented like this:

Dim result As Byte = CByte(leftOperand << (rightOperand And 7))

and the short operator:

Dim result As Short = CShort(leftOperand << (rightOperand And 15))

The corresponding C# operation is:

Dim result As Integer = CInt(leftOperand) << CInt(rightOperand)

Or CLng() if required. Implicit in C# code is that the programmer always has to cast the result back to the desired result type. There are a lot of SO questions about that from programmers that don't think that's very intuitive. VB.NET has another feature that makes automatic casting more survivable, it has overflow checking enabled by default. Although that's not applicable to shifts.

查看更多
Anthone
3楼-- · 2020-02-26 08:12

According to http://msdn.microsoft.com/en-us/library/a1sway8w.aspx byte does not have << defined on it for C# (only int, uint, long and ulong. This means that it will use an implciit conversion to a type that it can use so it converts it to int before doing the bit shift.

http://msdn.microsoft.com/en-us/library/7haw1dex.aspx says that VB defines the operation on Bytes. To prevent overflow it applies a mask to your shift to bring it within an appropriate range so it is actually in this case shifting by nothing at all.

As to why C# doesn't define shifting on bytes I can't tell you.

To actually make it behave the same for other datatypes you need to just mask your shift number by 7 for bytes or 15 for shorts (see second link for info).

查看更多
做个烂人
4楼-- · 2020-02-26 08:13

To apply the same in C#, you would use

static byte LeftShiftVBStyle(byte value, int count)
{
    return (byte)(value << (count & 7));
}

as for why VB took that approach.... just different language, different rules (it is a natural extension of the way C# handles shifting of int/&31 and long/&63, to be fair).

查看更多
登录 后发表回答