Что происходит с предыдущим "новым" оператором?

DispatcherTimer dt = new DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 0, 0, 100);
dt.Tick += new EventHandler(dt_dt);

У меня вопрос о new ключевом слове. У меня есть DispatcherTimer, который я установил на интервал. Допустим, пользователь хочет изменить интервал.

dt.Interval = new TimeSpan(0, 0, 0, 0, 50);

Итак, что происходит с первым new TimeSpan? Он все еще там? Или новый отменяет предыдущий? Я не думаю, что это так.

И если я хочу изменить интервал, является ли new ключевое слово единственным способом объявить новый TimeSpan? Я спрашиваю об этом, так как Im не уверен, действительно ли это нормально или даже право объявлять новый TimeSpan каждый раз при изменении значения.

Ответ 1

У вас есть класс (DispatcherTimer), который имеет поле типа TimeSpan, а TimeSpan - это структура.

Так как это структура - она "встроена" в экземпляр DispatcherTimer. Таким образом, экземпляр DispatcherTimer выглядит в памяти следующим образом:

<various metadata>...<contents of timespan>...

Если бы это был класс (ссылочный тип), он выглядел бы так:

<various metadata>...<reference to timespan>...

Когда вы это сделаете

dt.Interval = new TimeSpan( 0, 0, 0, 0, 50); 

В этом случае экземпляр TimeSpan выделяется (в стеке) и копируется в область памяти экземпляра DispatcherTimer выделенную для Interval, перезаписывая то, что было до этого.

Таким образом, мы

<various metadata>...<contents of timespan 1>

и теперь у нас есть

<various metadata>...<contents of timespan 2>

Это означает, что старый интервал времени просто перезаписан, он не будет собираться сборщиком мусора, потому что нет ничего, что можно было бы собрать (вопреки тому, что принято в ответах).

По этой причине выполнение этого в замкнутом цикле также не является проблемой (хотя, конечно, нет причин). Рассмотрим этот код:

class ClassWithRefField {
    public TestClass Field;
}

class ClassWithStructField {
    public TestStruct Field;
}

class TestClass {
    public TestClass(int payload) {
        Payload = payload;
    }
    public int Payload;
}

struct TestStruct {
    public TestStruct(int payload)
    {
        Payload = payload;
    }
    public int Payload;
}

Тогда, если вы это сделаете:

static void Main(string[] args) {
    var f = new ClassWithRefField();
    while (true) {
        f.Field = new TestClass(1);
    }            
}

И наблюдайте память процесса даже в проводнике процессов в окнах - вы увидите, что память постоянно растет и падает. Эти экземпляры TestClass создаются в куче и собираются сборщиком мусора.

Однако, если вы это сделаете:

static void Main(string[] args) {
    var f = new ClassWithStructField();
    while (true) {
        f.Field = new TestStruct(1);
    }            
}

Память в проводнике процесса останется неизменной, потому что тот же регион памяти постоянно перезаписывается, поэтому собирать нечего. Этот цикл может работать вечно.

И да - это нормально делать так, как вы делаете.

Ответ 2

Ну, здесь есть несколько вещей. Да, он создает второй экземпляр структуры TimeSpan. Поскольку первый нигде не упоминается, он выйдет за рамки и будет очищен сборщиком мусора. Никто не пострадал.

Если TimeSpan был бы классом, вы, вероятно, измените одно из свойств, но это структура, а структуры обычно неизменяемы, то есть вы не можете изменить их значение. (Это связано с несколькими причинами, я бы предложил прочитать об этом)

Таким образом, единственный вариант, который у вас есть, - создать новый экземпляр структуры TimeSpan. Это не проблема, если вы не делаете этого в узком цикле (создавая минимум новых экземпляров за очень короткое время, потребляя много памяти).