BinaryReader.ReadUInt64()的效率

时间:2015-12-02 08:33:01

标签: c# binaryreader

当我在.NET BinaryReader类中遇到此代码时,我只是想优化一些代码:

[CLSCompliant(false)]
[__DynamicallyInvokable]
public virtual ulong ReadUInt64()
{
  this.FillBuffer(8);
  return (ulong) (uint) ((int) this.m_buffer[4] | (int) this.m_buffer[5] << 8 | (int) this.m_buffer[6] << 16 | (int) this.m_buffer[7] << 24) << 32 | (ulong) (uint) ((int) this.m_buffer[0] | (int) this.m_buffer[1] << 8 | (int) this.m_buffer[2] << 16 | (int) this.m_buffer[3] << 24);
}

我想知道为什么ulong在两个部分中移动然后组合而不是仅仅在0,8,16,...,56中移位。

我还想解释一下这里使用的多种铸件。

编辑:当我在安装了ReSharper的VS2013中输入时,显示如下:

enter image description here

正如你所看到的,第二个ulong变暗了,这意味着它甚至没有使用过。看来缺少一对括号。这是对的吗?

1 个答案:

答案 0 :(得分:3)

首先,让我们以一种更易读的形式重写它:

CREATE PROCEDURE [dbo].[UPDATE_TRAINEE_EVENTS]
    @EVENTID                int,
    @EVENTTYPEID            int,
    @EVENTDATE              datetime,
    @STAFFID                int,
    @REVIEWNO               int,
    @COMMENTS               varchar(2100),
    @DESTINYVERIFIED        int,
    @DESTINYVERIFIEDBY      int,
    @DESTINYVERIFIEDDATE    datetime,
    @REASONFORSUSPENSIONID  int,
    @RETURNTOWORKDATE       datetime,
    @ContactDetailsUpdated  int,
    @RETENTION_STATUS_ID    int,
    @RETENTION_REASON_ID    int,
    @NonReview              int,
    @FalsifiedEventReason   int,
    @SusReqReasonID         int,
    @SusReqReturnDate       datetime
AS
    ......

现在很清楚这是做什么的。

它将低32位和高32位组合成两个单独的(ulong)(uint)( (int) this.m_buffer[4] | (int) this.m_buffer[5] << 8 | (int) this.m_buffer[6] << 16 | (int) this.m_buffer[7] << 24) << 32 | (ulong)(uint)( (int) this.m_buffer[0] | (int) this.m_buffer[1] << 8 | (int) this.m_buffer[2] << 16 | (int) this.m_buffer[3] << 24) 值(通过在将它们转换为uint之后移动字节),然后将两个结果int值转换为int,将高32位移位32,最后将它们“或”运算得到结果。

这样做的原因是因为移位32位值比移位64位值更快。如果代码将所有字节转换为ulong然后移位它们,则会更慢。

另请注意,组合字节的顺序是“little endian”格式。

唯一显而易见的事情是第一次演员ulong,可能就是(ulong)(uint)。如果删除所有不必要的强制转换,它看起来像这样:

(ulong)

现在你可能想知道为什么你不能仅仅转变为(ulong)( buffer[4] | buffer[5] << 8 | buffer[6] << 16 | buffer[7] << 24) << 32 | (uint)( buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24); 而不是ulong

答案如下。假设代码是这样的:

uint

由于转换为(ulong)( buffer[4] | buffer[5] << 8 | buffer[6] << 16 | buffer[7] << 24) << 32 | (ulong)( // This seems more natural... buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24); ,表达式的第一部分使用ulong.operator<<()移位。这会返回(ulong)

然而,表达式的第二部分没有移位,当它与第一个表达式进行OR运算时,它会提示编译器警告:

警告CS0675:在符号扩展操作数上使用按位或运算符;考虑先投射到较小的无符号类型

Eric Lippert有a blog about this warning你应该阅读。

无论如何,因为在第一部分中投射到(ulong)而第二部分投射到(ulong)时看起来很奇怪,我相当肯定他们会进行完全明确的演员以避免混淆读者。