You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#自定义ShortBuffer实现异常,请求排查问题原因

移植Java.nio ShortBuffer到C#时的容量、位置及写入异常问题

我正在将Android库中的Java FSKModem代码移植到C#,由于C#没有Java.nio的ByteBuffer和ShortBuffer,自行实现了这两个类。其中ByteBuffer测试运行正常,但ShortBuffer出现以下异常:

  • 容量(Capacity)显示为6,预期应为3(对应3个short类型元素)
  • 初始位置(Position)为3而非0
  • HasRemaining()、Remaining()方法的计算逻辑不符合预期
  • 指定索引的Put()方法无法正确写入数据

测试代码与输出

Java测试代码

import java.nio.ShortBuffer;

public class ShortBufferTest {
    public static void main(String[] args) {
        ShortBuffer buffer = ShortBuffer.allocate(3);
        System.out.println("Capacity: " + buffer.capacity());
        System.out.println("Position: " + buffer.position());
        System.out.println("HasRemaining: " + buffer.hasRemaining());
        System.out.println("Remaining: " + buffer.remaining());
        
        buffer.put(0, (short)100);
        buffer.put(1, (short)200);
        buffer.put(2, (short)300);
        
        buffer.flip();
        while(buffer.hasRemaining()) {
            System.out.println("Element: " + buffer.get());
        }
    }
}

Java输出

Capacity: 3
Position: 0
HasRemaining: true
Remaining: 3
Element: 100
Element: 200
Element: 300

C#测试代码(自行实现的ShortBuffer)

public class ShortBufferTest {
    public static void Main() {
        var buffer = new ShortBuffer(new byte[6]);
        Console.WriteLine($"Capacity: {buffer.Capacity}");
        Console.WriteLine($"Position: {buffer.Position}");
        Console.WriteLine($"HasRemaining: {buffer.HasRemaining()}");
        Console.WriteLine($"Remaining: {buffer.Remaining()}");
        
        buffer.Put(0, (short)100);
        buffer.Put(1, (short)200);
        buffer.Put(2, (short)300);
        
        buffer.Flip();
        while(buffer.HasRemaining()) {
            Console.WriteLine($"Element: {buffer.Get()}");
        }
    }
}

C#异常输出

Capacity: 6
Position: 3
HasRemaining: false
Remaining: 0
Element: 0
Element: 0
Element: 0

问题排查与修正方向

1. 容量计算错误

Java的ShortBuffer容量是short元素的个数,而C#如果用byte[]作为底层存储,容量应等于byte数组长度 / 2。如果你的实现直接将byte数组长度作为ShortBuffer的Capacity,就会出现6(对应6字节=3个short)的错误值。

2. 初始Position与Limit设置错误

Java中ShortBuffer默认初始Position为0,Limit等于Capacity。检查C#实现的构造函数,是否错误地将Position设为byte数组长度/2,或者Limit未正确绑定到short元素个数。

3. Remaining/HasRemaining逻辑错误

Java中Remaining() = Limit - Position,HasRemaining()判断Remaining() > 0。如果你的C#实现中Limit使用了byte数组长度而非short元素个数,会导致计算逻辑完全错误。

4. 指定索引Put方法的字节偏移与端序问题

Java的Put(int index, short value)直接操作对应索引的short位置,而C#底层用byte数组时:

  • 需计算正确的字节偏移量:index * 2
  • 注意端序匹配:Java ByteBuffer默认是大端序,而C# BitConverter默认是小端序,需要手动反转字节确保一致性

修正后的ShortBuffer核心实现示例

public class ShortBuffer
{
    private readonly byte[] _underlyingBytes;
    private int _position;
    private int _limit;
    private readonly bool _isBigEndian;

    public int Capacity => _underlyingBytes.Length / 2;
    public int Position
    {
        get => _position;
        set
        {
            if (value < 0 || value > _limit)
                throw new ArgumentOutOfRangeException(nameof(value));
            _position = value;
        }
    }
    public int Limit
    {
        get => _limit;
        set
        {
            if (value < 0 || value > Capacity)
                throw new ArgumentOutOfRangeException(nameof(value));
            _limit = value;
            if (_position > _limit)
                _position = _limit;
        }
    }

    public ShortBuffer(byte[] underlyingBytes, bool isBigEndian = true)
    {
        if (underlyingBytes.Length % 2 != 0)
            throw new ArgumentException("底层字节数组长度必须为偶数");
        _underlyingBytes = underlyingBytes;
        _isBigEndian = isBigEndian;
        _position = 0;
        _limit = Capacity;
    }

    public int Remaining() => _limit - _position;
    public bool HasRemaining() => Remaining() > 0;

    public void Put(int index, short value)
    {
        if (index < 0 || index >= Capacity)
            throw new ArgumentOutOfRangeException(nameof(index));
        
        int byteOffset = index * 2;
        byte[] shortBytes = BitConverter.GetBytes(value);
        // 匹配Java大端序
        if (BitConverter.IsLittleEndian != _isBigEndian)
            Array.Reverse(shortBytes);
        
        _underlyingBytes[byteOffset] = shortBytes[0];
        _underlyingBytes[byteOffset + 1] = shortBytes[1];
    }

    public short Get()
    {
        if (!HasRemaining())
            throw new InvalidOperationException("无剩余元素");
        
        int byteOffset = _position * 2;
        byte[] shortBytes = new byte[2];
        shortBytes[0] = _underlyingBytes[byteOffset];
        shortBytes[1] = _underlyingBytes[byteOffset + 1];
        
        if (BitConverter.IsLittleEndian != _isBigEndian)
            Array.Reverse(shortBytes);
        
        _position++;
        return BitConverter.ToInt16(shortBytes, 0);
    }

    public void Flip()
    {
        _limit = _position;
        _position = 0;
    }
}

内容的提问来源于stack exchange,提问作者LimetaPeta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:43:25