0

我有一个Octet类应该“打包”八个样本,然后将它们发送出去。它具有添加新样本、检查其是否已满以及FrameOctet.

该类Octet抛出两种异常:“无法提取,因为尚未满”和“无法添加样本,因为已经满”。为此,客户端代码应在调用之前检查是否已满Add,并在已满时立即提取,并重置它(老实说,这是一个很蹩脚的类合约)。

问题是:我得到了两种错误,即使客户端类 - 唯一使用的Octet- 似乎在抛出的操作之前正确地执行了检查,但即使错误条件被击中。更糟糕的是,当我在调试器中断时检查值时,它们是正确的,也就是说,不应该抛出异常!

public class Client
{
    private Octet _octet = new Octet();

    void ProcessNewSamples(IEnumerable<int> newSamples)
    {
        foreach (int sample in newSamples)
        {
            if (!_octet.IsFull)
            {
                _octet.Add(sample);
            }

            if (_octet.IsFull)
            {
                var frame = _octet.ExtractFrame();
                this.SendElsewhere(frame);
                _octet.Reset();
            }

        }
    }
}


public class Octet
{
    const int ARRAY_SIZE = 8;
    int[] _samples = new int[ARRAY_SIZE];
    int _index = 0;

    public bool IsFull { get { return _index >= 8; } }

    public void Add(int sample)
    {
        if (IsFull)
        {
            throw new InvalidOperationException();
        }
        else
            _samples[_index++] = sample;
    }

    public Frame<int> ExtractFrame()
    {
        if (!IsFull)
            throw new InvalidOperationException();
        else
            return new Frame<int>(_samples);

    }

    public void Reset()
    {
        _samples = new int[ARRAY_SIZE];
        _index = 0;
    }
}
4

1 回答 1

2

正如评论中提到的,如果您的函数被并行访问,您应该放置一个锁。

如果SendElsewhere速度很快,我只需将锁放在函数周围:

void ProcessNewSamples(IEnumerable<int> newSamples)
{
    lock (this)
    {
        foreach (int sample in newSamples)
        {
            if (!_octet.IsFull)
            {
                _octet.Add(sample);
            }

            if (_octet.IsFull)
            {
                var frame = _octet.ExtractFrame();
                this.SendElsewhere(frame);
                _octet.Reset();
            }
        }
    }
}

否则我会收集所有帧并在之后发送它们:

void ProcessNewSamples(IEnumerable<int> newSamples)
{
    var frames = new List<Frame>();

    lock (this)
    {
        foreach (int sample in newSamples)
        {
            if (!_octet.IsFull)
            {
                _octet.Add(sample);
            }

            if (_octet.IsFull)
            {
                var frame = _octet.ExtractFrame();
                frames.Add(frame);
                _octet.Reset();
            }
        }
    }

    foreach (var frame in frames)
    {
        this.SendElsewhere(frame)
    }
}
于 2016-09-19T20:03:12.020 回答