Делает обнуление System.Threading.Timer остановить его?

Если у меня есть активный System.Threading.Timer, и я установил его в null, он остановлен?

Я понимаю, что правильнее называть .Dispose(), но я хотел бы ответить на вопрос, как написано.

public class Foo
{
   private System.Threading.Timer _timer;
   public Foo()
   {
      // initialize timer
   }

   public void KillTimer()
   {
      _timer=null;
   }
}

Обновление:

После многого назад о том, будет ли установка единственной ссылки на System.Threading.Timer на null, действительно приведет к остановке, она показала, что

  • нет никаких затяжных ссылок, например. список событий, поскольку таймер потоковой передачи принимает обратный вызов sinlge и не выдает события.
  • что GC , если собирает GC, финализатор действительно удалит TimerBase и остановит таймер.

шип

using System;
using System.Threading;

namespace SO_3597276
{
    class Program
    {
        private static System.Threading.Timer _timer;

        static void Main(string[] args)
        {
            _timer = new Timer((s) => Console.WriteLine("fired"), null, 1000, Timeout.Infinite);
            _timer = null;
            GC.Collect();
            Console.ReadKey();
        }
    }
}

Обратный вызов таймера не вызывается. Удалите GC.Collect() и вызывается обратный вызов.

Спасибо всем.

Ответы

Ответ 1

Не обязательно. Устанавливая его на нуль, удаляет любые ссылки на него и полагается на сборщик мусора, чтобы избавиться от него.

Если таймер погас до того, как GC дошел до него, это вызовет событие.

Ответ 2

Почему?

Рассмотрим:

  System.Threading.Timer t = ...;
  System.Threading.Timer q = t;
  q = null; // Should this stop it as well?

Настройка на null - это то, что вы делаете с переменной, а не с тем, что вы делаете с объектом. Таймер не может знать, что вы задали конкретную переменную в значение null и не можете предпринимать действия на основе этого.

EDIT:

Чтобы обратиться к редактированию, даже в случае наличия единственной ссылки, не гарантируется, что таймер будет остановлен, так как это возможно, GC может не работать после того, как ссылка была установлена ​​в значение null. Это также не совсем маловероятно: реализация Microsoft.NET использует коллектора поколений, а статическое поле, скорее всего, выживет в детской коллекции и будет переведено в более старшее поколение. Если ваша программа имеет относительно стабильный профиль памяти, никогда не может быть коллекция из более старых поколений (и по расширению финализатор не будет работать до конца программы).

Ответ 3

Я знаю, что вы спрашиваете о классе System.Threading.Timer, но я хочу указать на что-то весьма важное.

Ответы, представленные до сих пор, хороши. Logan и SLaks правильны, что установка любой переменной в null не оказывает прямого воздействия на объект, к которому переменная была ранее назначена. Рассел прав, что, когда сборщик мусора в конечном итоге утилизирует таймер, он остановится.

SLaks указал, что после установки ссылки на таймер на null могут существовать затяжные ссылки. В простом примере одной ссылки System.Threading.Timer это не так.

Но, если у вас есть, например, System.Timers.Timer, и вы обрабатываете его Elapsed, а затем установите для параметра null значение оставить ссылку, а таймер будет продолжать работать навсегда.

Итак, рассмотрите этот код, например:

var t = new System.Timers.Timer(1000.0);
t.AutoReset = true;
t.Elapsed += (sender, e) => Console.WriteLine(DateTime.Now);

Console.Write("Press Enter to start the timer.");
Console.ReadLine();
t.Start();

Console.Write("Press Enter to set t to null.");
Console.ReadLine();

// This will not stop the timer. It actually does nothing at all to the timer
// to which t has been assigned.
t = null;

Console.Write("Press Enter again to perform a garbage collection.");
Console.ReadLine();

// This STILL will not stop the timer, as t was not the only reference to it
// (we created a new one when we added a handler to the Elapsed event).
GC.Collect();

Console.Write("t is null and garbage has been collected. Press Enter to quit.");
Console.ReadLine();

В приведенном выше примере, поскольку код, удерживающий ссылку на t для обработки своего события Elapsed, таймер никогда не останавливается.

Опять же, я понимаю, что это не тот класс, о котором вы спрашивали; Я лишь объясняю это тем, что не всегда очевидно, действительно ли у вас есть или больше нет ссылок на данный объект.


ОБНОВЛЕНИЕ. Похоже, возникла некоторая путаница в вопросе о том, относится ли утверждение, которое я сделал выше, к объекту System.Threading.Timer; это не. Чтобы убедиться в этом, рассмотрите следующую модификацию приведенного выше кода:

Console.Write("Press Enter to start the timer.");
Console.ReadLine();

var t = new System.Threading.Timer(
    state => { Console.WriteLine(DateTime.Now); },
    null,
    0,
    1000
);

Console.Write("Press Enter to set t to null.");
Console.ReadLine();

// This will not stop the timer. It actually does nothing at all to the timer
// to which t has been assigned. HOWEVER, if/when the GC comes around to collect
// garbage, it will see that said timer has no active references; and so it will
// collect (and therefore finalize) it.
t = null;

Console.Write("Press Enter again to perform a garbage collection.");
Console.ReadLine();

// This WILL cause the timer to stop, as there is code in the type's
// finalizer to stop it.
GC.Collect();

Console.Write("t is null and garbage has been collected. Press Enter to quit.");
Console.ReadLine();

Вот почему это не работает для System.Timers.Timer (или любого типа, который имеет события, фактически):

Ответ очень прост, если мы определили наш обработчик событий следующим образом:

t.Elapsed += (sender, e) => Console.WriteLine(DateTime.Now);

Что делать, если вместо этого я определил свой обработчик?

t.Elapsed += (sender, e) => Console.WriteLine(sender.GetType());

О, верно! Этот аргумент sender, на который никто никогда не обращает внимания!

Инфраструктура обработки событий, предоставляемая .NET, требует, чтобы объекты, обрабатывающие события, поддерживали ссылки на объекты, поднимающие события. В противном случае договор, предоставленный самой подписью делегата EventHandler и всех его кузенов, будет нарушен.

Мораль этой истории: как только вы добавляете обработчик события, вы создали новую ссылку на объект. Единственный способ разрешить сборку этого мусора после этого момента - удалить обработчик, но это может быть довольно сложно, если вы установили единственную ссылку на указанный объект на null (это один из самых несколько примеров случая, когда .NET-программа может иметь "утечку памяти" ).

Ответ 4

Нет, это не остановится.

Установка переменной в null не имеет непосредственных побочных эффектов, таких как остановка таймера. (Если это не свойство)

Поскольку таймер имеет другие ссылки, GC не будет его собирать, и он никогда не остановится.