E
E
eRKa2016-07-26 13:53:39
.NET
eRKa, 2016-07-26 13:53:39

Is there such an implemented list in C#?

The task needs a list that would generate an event when a record appears in it and in which you can specify the lifetime of the record. Well, with the generation of an event about a record, it is easier, there is such a thing, but I did not find it with an indication of how long this record should stay there. Maybe someone knows if there are ready-made solutions or will you have to decide by hand?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
M
Maa-Kut, 2016-07-26
@kttotto

Alternatively, you can use MemoryCache: stackoverflow.com/questions/7435832/c-sharp-list-w...

O
Ogoun Er, 2016-07-27
@Ogoun

To solve a similar problem, I used my own solution, where I made a singly linked list of objects wrapping my object and adding a field with the deletion time. The list object class contains one timer, from Threading. When adding a new object, it is inserted sorted by date, i.e. the first object in the list is always the one with the shortest lifetime, when adding/removing the timer is recalculated. As a result, few resources are consumed, but the complexity of insertion / deletion is O (N)
Here is a simplified working example:

internal class TemporaryObject
{
    private static long _counter = 0;
    public long Key { get; private set; }
    public TemporaryObject()
    {
        Key = Interlocked.Increment(ref _counter);
    }
    /// <summary>
    /// Событие при завершении ожидания
    /// </summary>
    public Action Callback;
    /// <summary>
    /// Срок истечения ожидания
    /// </summary>
    public DateTime ExpirationDate;
    /// <summary>
    /// Следующий объект с ближайшей датой окончания ожидания
    /// </summary>
    public TemporaryObject Next;
}

public class TemporaryObjectPool
{
    private readonly object _locker = new object();
    /// <summary>
    /// Таймер. Один на всех
    /// </summary>
    private Timer _timer;
    /// <summary>
    /// Объект с ближайшей датой окончания ожидания
    /// </summary>
    private TemporaryObject _current = null;
    /// <summary>
    /// Переустановка таймера
    /// </summary>
    private void ResetTimer()
    {
        if (null != _current)
        {
            var diff = (_current.ExpirationDate - DateTime.Now).TotalMilliseconds;
            if (diff < 0) diff = 0;
            _timer.Change((int)diff, Timeout.Infinite);
        }
        else
        {
            _timer.Change(Timeout.Infinite, Timeout.Infinite);
        }
    }

    public TemporaryObjectPool()
    {
        _timer = new Timer(state =>
        {
            Action action = null;
            lock (_locker)
            {
                if (null != _current)
                {
                    // Получаем событие для исполнения
                    action = _current.Callback;
                    // Находим следующий ожидающий объект
                    _current = _current.Next;
                    // Перезадание таймера
                    ResetTimer();
                }
            }
            // Вызов события ожидавшего даты
            if (null != action)
            {
                ThreadPool.QueueUserWorkItem(s => action());
            }
        }, null, Timeout.Infinite, Timeout.Infinite);
    }

    /// <summary>
    /// Добавление ожидающего объекта
    /// </summary>
    /// <param name="insert"></param>
    internal long Push(TemporaryObject insert)
    {
        lock (_locker)
        {
            // Если пул пуст, то добавляемое событие становится корневым
            if (null == _current)
            {
                _current = insert;
            }
            else
            {
                // Если пул не пуст
                var cursor = _current;
                TemporaryObject prev = null;
                // Поиск места для вставки, сложность вставки O(n) в худшем случае
                do
                {
                    if (DateTime.Compare(cursor.ExpirationDate, insert.ExpirationDate) > 0)
                    {
                        insert.Next = cursor;
                        if (null == prev)
                        {
                            _current = insert;
                        }
                        else
                        {
                            prev.Next = insert;
                        }
                        break;
                    }
                    prev = cursor;
                    cursor = cursor.Next;
                    if (cursor == null)
                    {
                        prev.Next = insert;
                    }
                } while (cursor != null);
            }
            ResetTimer();
        }
        return insert.Key;
    }

    public void Remove(long key)
    {
        lock (_locker)
        {
            if (_current == null) return;
            bool removed = false;
            if (_current.Key == key)
            {
                _current = _current.Next;
                removed = true;
            }
            else
            {
                var prev = _current;
                var next = _current.Next;
                while (next != null)
                {
                    if (next.Key == key)
                    {
                        prev.Next = next.Next;
                        removed = true;
                        break;
                    }
                    prev = next;
                    next = next.Next;
                }
            }
            if (removed)
            {
                ResetTimer();
            }
        }
    }
}

and use
var pool = new TemporaryObjectPool();
pool.Push(new TemporaryObject { Callback = () => Console.WriteLine("#1 removed"), ExpirationDate = DateTime.Now.AddSeconds(5) });
pool.Push(new TemporaryObject { Callback = () => Console.WriteLine("#2 removed"), ExpirationDate = DateTime.Now.AddSeconds(10) });
pool.Push(new TemporaryObject { Callback = () => Console.WriteLine("#3 removed"), ExpirationDate = DateTime.Now.AddSeconds(15) });

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question