C# 连续保存数据

C# 连续保存数据,c#,C#,我有一个物体随着时间在空间中移动,我想每0.5秒保存它的位置(x,y,z),总共10秒。物体将不断移动,但我只想要最新的10秒 我一直在考虑使用数组[20],但这意味着每0.5秒我必须弹出最后一个元素(比如数据[19]),在之前推送每个元素,并在数据[0]处添加当前元素 有没有更优雅的方法 编辑:性能可能是一个问题,因为我将保存这些对象的大量数据。这就是为什么我在寻找一种聪明的方法。提前感谢:)如评论中所述,您可以使用 下面是一个示例实现 /// <summary> /// A ci

我有一个物体随着时间在空间中移动,我想每0.5秒保存它的位置(x,y,z),总共10秒。物体将不断移动,但我只想要最新的10秒

我一直在考虑使用数组[20],但这意味着每0.5秒我必须弹出最后一个元素(比如数据[19]),在之前推送每个元素,并在数据[0]处添加当前元素

有没有更优雅的方法


编辑:性能可能是一个问题,因为我将保存这些对象的大量数据。这就是为什么我在寻找一种聪明的方法。提前感谢:)

如评论中所述,您可以使用

下面是一个示例实现

/// <summary>
/// A circular buffer with a maximum capacity set at construction time.
/// You can repeatedly add elements to this buffer; once it has reached its capacity
/// the oldest elements in it will be overwritten with the newly added ones.
/// This is how it differs from a queue: Oldest elements will be overwritten when the buffer is full.
/// </summary>
/// <typeparam name="T">The type of the elements stored in the buffer.</typeparam>

[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "Calling this CircularBufferCollection would be stupid.")]

public class CircularBuffer<T>: IEnumerable<T>
{
    /// <summary>Constructor.</summary>
    /// <param name="capacity">The maximum capacity of the buffer.</param>

    public CircularBuffer(int capacity)
    {
        Contract.Requires<ArgumentOutOfRangeException>(capacity > 0, "Capacity must be greater than zero.");

        // We will use a buffer with a size one greater than the capacity.
        // The reason for this is to simplify the logic - we can use "front == back" to indicate an empty buffer.

        _buffer = new T[capacity+1];
    }

    /// <summary>The buffer capacity.</summary>

    public int Capacity
    {
        get
        {
            Contract.Ensures(Contract.Result<int>() > 0);
            return _buffer.Length - 1;
        }
    }

    /// <summary>The number of elements currently stored in the buffer.</summary>

    public int Count
    {
        get
        {
            Contract.Ensures(0 <= Contract.Result<int>() && Contract.Result<int>() <= this.Capacity);

            int result = _back - _front;

            if (result < 0)
            {
                result += _buffer.Length;
            }

            return result;
        }
    }

    /// <summary>Is the buffer empty?</summary>

    public bool IsEmpty
    {
        get
        {
            return this.Count == 0;
        }
    }

    /// <summary>Is the buffer full? (i.e. has it reached its capacity?)</summary>

    public bool IsFull
    {
        get
        {
            return nextSlot(_back) == _front;
        }
    }

    /// <summary>Empties the buffer.</summary>

    public void Empty()
    {
        Contract.Ensures(this.IsEmpty);

        _front = _back = 0;
        Array.Clear(_buffer, 0, _buffer.Length); // Destroy any old references so they can be GCed.
    }

    /// <summary>Add an element to the buffer, overwriting the oldest element if the buffer is full.</summary>
    /// <param name="newItem">The element to add.</param>

    public void Add(T newItem)
    {
        _buffer[_back] = newItem;
        _back = nextSlot(_back);

        if (_back == _front) // Buffer is full?
        {
            _front = nextSlot(_front); // Bump the front, overwriting the current front.
            _buffer[_back] = default(T); // Remove the old front value.
        }
    }

    /// <summary>Removes and returns the oldest element from the buffer.</summary>
    /// <returns>The element that was removed from the buffer.</returns>
    /// <exception cref="InvalidOperationException">Thrown if the buffer is empty.</exception>

    public T RemoveOldestElement()
    {
        Contract.Requires<InvalidOperationException>(!this.IsEmpty, "Cannot remove an element from an empty buffer.");

        T result = _buffer[_front];
        _buffer[_front] = default(T); // Zap the front element.
        _front = nextSlot(_front);

        return result;
    }

    /// <summary>
    /// The typesafe enumerator. Elements are returned in oldest to newest order.
    /// This is not threadsafe, so if you are enumerating the buffer while another thread is changing it you will run
    /// into threading problems. Therefore you must use your own locking scheme to avoid the problem.
    /// </summary>

    public IEnumerator<T> GetEnumerator()
    {
        for (int i = _front; i != _back; i = nextSlot(i))
        {
            yield return _buffer[i];
        }
    }

    /// <summary>The non-typesafe enumerator.</summary>

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator(); // Implement in terms of the typesafe enumerator.
    }
    /// <summary>Calculates the index of the slot following the specified one, wrapping if necessary.</summary>

    private int nextSlot(int slot)
    {
        return (slot + 1) % _buffer.Length;
    }

    /// <summary>
    /// The index of the element at the front of the buffer. 
    /// If this equals _back, the buffer is empty.
    /// </summary>

    private int _front;

    /// <summary>
    /// The index of the first element BEYOND the last used element of the buffer. 
    /// Therefore this indicates where the next added element will go.
    /// </summary>

    private int _back;

    /// <summary>The underlying buffer. This has a length one greater than the actual capacity.</summary>

    private readonly T[] _buffer;
}
//
///在构造时设置最大容量的循环缓冲区。
///您可以重复向该缓冲区添加元素;一旦达到其容量
///其中最古老的元素将被新添加的元素覆盖。
///这就是它与队列的不同之处:当缓冲区已满时,最旧的元素将被覆盖。
/// 
///缓冲区中存储的元素的类型。
[SuppressMessage(“Microsoft.Naming”、“CA1710:IdentifiersShouldHaveCorrectSuffix”、Justification=“调用此CircularBufferCollection将是愚蠢的。”)]
公共类循环缓冲区:IEnumerable
{
///构造器。
///缓冲区的最大容量。
公共循环缓冲器(国际容量)
{
合同要求(容量>0,“容量必须大于零”);
//我们将使用一个大小大于容量的缓冲区。
//这样做的原因是为了简化逻辑-我们可以使用“front==back”来表示空缓冲区。
_缓冲区=新T[容量+1];
}
///缓冲区容量。
公共int容量
{
得到
{
Contract.Result(Contract.Result()>0);
返回_buffer.Length-1;
}
}
///当前存储在缓冲区中的元素数。
公共整数计数
{
得到
{

确保(0正如@zerkms所说,您正在寻找一个循环缓冲区

您可以从a或a构建它。其思想是在列表末尾添加新元素,如果达到最大大小,则删除第一个元素

你也可以从数组中构建它。这个想法是在列表的开头和结尾有两个索引,然后通过循环(使用模)遍历数组。另外,当
startIndex==endIndex
时,你将不知道列表是空的还是满的,因此你必须使用一个布尔值来知道这一点。请详细介绍一下

最后一个通常是首选的,因为您将使用同一个位置来存储对象。虽然在C#中只存储引用,它们不会占用太多空间


谷歌将为您提供大量实现这一点的工具。

您可以使用


如果用于跟踪x个最新事件。
Enqueue()
每个事件,然后
Dequeue()
直到
队列
包含您想要保留的事件数。

研究关键字:循环缓冲区正是我想要的,非常感谢。c#队列可能就是我想要的,只是为了指出此
GetEnumerator
实现不是修改安全的。如果对集合进行了更改,例如添加、修改或删除元素时,枚举数将不可恢复地失效,下一次调用MoveNext或Reset将引发InvalidOperationException。