在没有内存分配的情况下在 C# 中将 float/double/decimal 转换为 (u)int、(u)long

Converting float/double/decimal to (u)int, (u)long in C# without memory allocation

我正在为我的游戏开发 c# 网络解决方案,我在序列化 floats、doubles 和 decimals 时遇到问题。

我的第一次尝试 - BitConverter class。但是每次我使用 class 时,都会创建一个新的 byte[] 数组,这对于我的网络解决方案(例如 - 玩家位置同步)来说可能有点过头了。

总而言之,我的期望是:

编辑 1

这是我在 NetworkWriter 方法中用来存储要发送的字节的方法:

public void WriteByte(byte value)
        {
            Buffer[_position++] = value;
        }

这些是我对 NetworkWriter 的扩展:

public static void WriteUInt(this NetworkWriter writer, uint value)
        {
            writer.WriteByte((byte) value);
            writer.WriteByte((byte) (value >> 8));
            writer.WriteByte((byte) (value >> 16));
            writer.WriteByte((byte) (value >> 24));
        }

我想将 4 字节浮点数转换为 4 字节 (u)int,这样我就可以将结果 int 传递给 Write(U)Int 序列化程序。

我还没有完成 NetworkReader,所以我不能告诉你确切的代码,但它会恢复 Write 方法。

我预计会有很多 float/double 操作,因为:

这就是为什么我想尽可能减少 float/double/decimal 的内存分配。

编辑 2

重要说明:我知道什么时候需要 float、double 等,让我快速伪代码 reader 看起来像什么:

static float ReadFloat():
- Get 4 int bytes from buffer
- Construct float from those

很多选项:

  • BitConverter 有类似 Int32BitsToSingle(Int32) 的方法(从和到,32 位和 64 位),在基元之间进行按位强制转换;从那里你可以得到 unsigned 平凡
  • BinaryPrimitives 为许多在 span 上工作的原语提供了读写方法;跨度可以在堆栈上以进行零分配(或者更好:可以在您的输出缓冲区中)
  • 你自己的unsafe代码;获取 a local/parameter/field/interior-pointer 的地址,并在取消引用之前强制指针
  • Unsafe 类型(尤其是 As 方法)允许来自 ref 的相同大小基元之间的直接强制转换(类似于 unsafe 选项,但是预先编写,并使用 IL 来避免非托管指针)
  • MemoryMarshal 类型(尤其是 Cast 方法)允许在 spans 类型上进行相同的直接转换,包括不同大小的类型之间;特别是,这允许您将任何不包含引用的原语转换为 Span<byte>