属性似乎在方法调用之间改变,但没有代码应该改变它



我有一个Octet类,应该"包装"8个样品,然后将它们发送出去。它有方法添加一个新的样本,检查它是否已经满了,并从Octet的八个值中提取一个Frame数据结构。

Octet类抛出两种异常:"未满不能提取"one_answers"已满不能添加样本"。为此,客户端代码应该在调用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;
    }
}

正如在注释中提到的,如果函数是并行访问的,那么应该设置一个锁。

如果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)
    }
}

最新更新