События и сборка мусора в c#

79
26 марта 2021, 04:50

Начал изучать концепцию событий в c#. У меня есть следующие классы:

class CustomTimer
    {
        public delegate void DateAndTimeHandler(DateTime dateTime);
        DateAndTimeHandler dateOrTimeUpdated;
        public event DateAndTimeHandler DateOrTimeUpdated
        {
            add { lock (this) dateOrTimeUpdated += value; }
            remove { lock (this) dateOrTimeUpdated -= value; }
        }
        public CustomTimer()
        {
            InitialStartedTime = DateTime.Now;
            int num = 0;
            TimerCallback tm = new TimerCallback(ProcessTime);
            System.Threading.Timer timer = new System.Threading.Timer(tm, num, 0, 1000);
        }
        private void ProcessTime(object obj)
        {
            dateOrTimeUpdated?.Invoke(DateTime.Now);
        }
    }
    class SuperCore
    {
        public CustomTimer timer = new CustomTimer();
    }

И небольшой пример работы с этими классами в WinForms:

public partial class Form1 : Form
{
    public string StringTime
    {
        get { try { return label1.Text; } catch { return ""; }; }
        set { try { Invoke(new Action(() => { label1.Text = value; })); } catch { } }
    }
    SuperCore superCore = new SuperCore();
    public Form1()
    {
        InitializeComponent();
        superCore.timer.DateOrTimeUpdated += TimeUpdate;
    }
    void TimeUpdate(DateTime dt)
    {
        StringTime = dt.ToString();
    }
    private void button1_Click(object sender, EventArgs e)
    {
        GC.Collect();
    }
}

Я заметил, что при сборке мусора у меня перестает обновляться время на label1, т.е. происходит уничтожение события. Чтобы проверить это и убедиться, что так и есть, я при нажатии на button1 вызываю сборщик мусора. Гипотеза подтвердилась.

Это приложение является просто демонстрацией проблемы.

Вопрос: Как мне сделать так, чтобы подписка на событие сохранялась? Чтобы время обновлялось на label1?

Answer 1

Необходимо сделать timer полем класса CustomTimer. Код класса CustomTimer будет выглядеть так:

class CustomTimer
{
    public delegate void DateAndTimeHandler(DateTime dateTime);
    DateAndTimeHandler dateOrTimeUpdated;
    public event DateAndTimeHandler DateOrTimeUpdated
    {
        add { lock (this) dateOrTimeUpdated += value; }
        remove { lock (this) dateOrTimeUpdated -= value; }
    }
    System.Threading.Timer timer;
    public CustomTimer()
    {
        int num = 0;
        TimerCallback tm = new TimerCallback(ProcessTime);
        timer = new System.Threading.Timer(tm, num, 0, 1000);
    }
    private void ProcessTime(object obj)
    {
        dateOrTimeUpdated?.Invoke(DateTime.Now);
    }
}

За ответ в комментариях на вопрос спасибо Alexander Petrov и tym32167.

READ ALSO
Как удалить контрольные точки windows?

Как удалить контрольные точки windows?

За основу взят этот код, я его немного переделал

106
Как правильно вычислить дату в sql запросе?

Как правильно вычислить дату в sql запросе?

Есть задача, сделать выборку в таблице по возрасту - до ЛЕТДата рождения хранится в типе поля date

93