объяснить, почему объект имеет время жизни вне области видимости

Я написал класс следующим образом. Я написал его с учетом того, что он в основном предназначен для использования в Интернете (т.е. он будет использоваться со страниц aspx).

public class TestHelper
{    
    public TestHelper()
    {
        HttpContext ctxt = HttpContext.Current;
        IHttpHandler RequestHandler = ctxt.Handler;
        Page CurrentPage;
        CurrentPage = (Page)RequestHandler;
        CurrentPage.Unload += new EventHandler(CurrentPage_Unload); 
        Debug.Print("Open all connection here...");
    }

    void CurrentPage_Unload(object sender, EventArgs e)
    {
        Debug.Print("Close all connection here...");
    }
}

И я написал код своей страницы aspx следующим образом:

public partial class _Default : System.Web.UI.Page 
{    
    protected void Page_Load(object sender, EventArgs e)
    {
        TestHelper helper = new TestHelper();
        helper = null;
    }

}

Несмотря на то, что помощнику присвоено значение «null», я обнаружил, что CurrentPage_Unload() выполняется. Почему такое поведение? Как обычно называется такое поведение?

Причина, по которой я написал класс в этом стиле, заключалась в том, что я думал, что смогу лучше всего управлять своими подключениями к базе данных централизованно в классе. Обычно люди вызывают методы для объекта, такие как helper.IsValid(), за которыми следует helper.ProfileExists() в коде aspx позади. Каждый из этих методов будет иметь свои собственные объекты соединения с БД (IDbConnection) и соответствующие им вызовы Open() и Close() для открытия/закрытия соединения с БД. Я просто чувствовал, что мы должны сделать это только один раз в коде. Поэтому я использовал конструктор для открытия соединений с БД и событие unload объекта Page для закрытия объектов соединения. Есть ли какие-то подводные камни в написании уроков таким образом?


person deostroll    schedule 19.07.2010    source источник
comment
Следует ли читать CurrentPage_Unload() там, где вы пишете CustomPage_Unload()?   -  person relet    schedule 19.07.2010


Ответы (3)


Присвоение null переменной не заканчивается ее фактическое время жизни. Поскольку .NET использует недетерминированную систему сборки мусора (где объекты периодически очищаются на основе нескольких критериев, а не сразу, как только они выпадают из области видимости), вы не можете полагаться на то, что объект когда-либо будет собран. до того, как завершится процесс, создавший его.

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

person Adam Robinson    schedule 19.07.2010
comment
Поскольку выгрузка страницы связана с методом класса, который я создаю, будет ли GC фактически собирать этот экземпляр класса? - person deostroll; 19.07.2010
comment
@deostroll: это то, что я пытаюсь понять во втором абзаце. Присоединение вашего объекта (this) к событию Unload события CurrentPage (ссылка, существующая вне вашего класса, поскольку она исходит из RequestHandler) означает, что ссылка на this сохраняется как часть обработчика события RequestHandler. Это означает, что ваш объект не подлежит сборке мусора до тех пор, пока не будет разрешен объект, указанный в RequestHandler, или пока вы не отсоединитесь от события. - person Adam Robinson; 19.07.2010

Происходит следующее: вы присоединяете делегата к событию Unload страницы. Даже после того, как ваша переменная была установлена ​​в значение null, ваша страница все еще существует и все еще имеет событие Unload, которое все еще содержит ссылку на добавленного вами делегата.

Чтобы удалить делегата, вам нужно использовать синтаксис -=.

CurrentPage.Unload -= new EventHandler(CurrentPage_Unload); 
person Greg B    schedule 19.07.2010

Вы должны думать о том, что происходит, когда вы выполняете строку

helper = null;

У вас просто есть ссылка на объект. Когда вы присваиваете этому объекту значение null, вы просто устанавливаете для своей ссылки значение null. С объектом ничего не произошло. Рассмотрим следующий код:

var first = new object();
second = first;

first = null;

Будет ли секунда теперь нулевой? Вы можете думать о ссылке просто как о числе — это просто адрес объекта в памяти.

Сборщик мусора .NET просто просматривает объекты и проверяет, есть ли ссылки на этот объект. Если нет, он удалит этот объект.

person Jaco Pretorius    schedule 19.07.2010