Я читал об управлении памятью и сталкивался с ситуацией в проекте, где книга или Google придумали точный ответ. Я уже знаю, что делегаты управляют объектами, а события - экземплярами делегата. Сказав это, экземпляры делегатов будут удалены из памяти после завершения приложения.Что делать с ссылками делегата/события в классе, который реализует IDisposable
Я не могу понять, как обеспечить, чтобы внешний код освободил все ссылки на события до того момента, как мой класс будет удален (явно или GC). В качестве примера класс A
раскрывает событие, а класс B
его использует. Класс B
вызывает Dispose в классе A
, не высвобождая ссылки на делегатов. Конечно, мы не можем выбросить ошибку из самого метода Dispose.
Ниже приведен класс с делегатом и другой, который его потребляет.
public class ClassB
{
private ClassA A { get; set; }
public ClassB()
{
this.A = new ClassA();
this.A.OnProcessed += new ClassA.DelegateProcessed(this.ClassA_Processed);
}
public void Process()
{
this.A.Process();
}
public void ClassA_Processed (ClassA sender, EventArgs e)
{
// Do something.
// Code written by another developer does not free up events before calling Dispose.
this.A.Dispose();
this.A = null;
}
}
public class ClassA: IDisposable
{
public delegate void DelegateProcessed (A sender, EventArgs e);
public event DelegateProcessed OnProcessed = null;
~ClassA() { this.Dispose(false); }
public void Dispose()
{
this.Dispose(true);
System.GC.SuppressFinalize(this);
}
private void Dispose (bool disposing)
{
if (!this.Disposed)
{
if (disposing)
{
// Dispose managed resources here.
// Is it possible/advisable to dispose of delegates/events here?
// Will this adversely affect the consumer class?
this.OnProcessed -= new ClassA.DelegateProcessed(this.ClassA_Processed);
}
}
this.Disposed = true;
}
public void Process() { this.OnProcessed(this, new EventArgs()); }
public void ClassA_Processed (ClassA sender, EventArgs e) { }
}
Цель состоит в том, чтобы гарантировать, что ClassA подходит для сбора мусора независимо от того, что делает разработчик с ClassB. Суть заключается в том, чтобы свести к минимуму количество времени, которое ClassA проводит в памяти, даже если потребитель небрежен.
ОБНОВЛЕНИЕ: Из ответов видно, что события не должны быть явно удалены из ClassA. Что касается основного вопроса, то, по-видимому, слабыми рекомендациями являются способы, как показано ниже. Цель состоит в том, чтобы минимизировать время, в течение которого ClassA остается в памяти. Пожалуйста, дайте мне знать в случае, если я упустил любой из них.
Здесь есть что-то о вашей логике. Это класс A, который будет содержать делегатов от cl ass B в списке вызовов 'OnProcessed', а не наоборот. – spender
@spender: я написал код в редакторе SO, поэтому может быть ошибка, но я не следую вашей точке. ClassA - это тот, у кого есть делегат, а classB содержит ссылку. Я пытаюсь удалить referecnce из ClassA, так что, даже если ClassB забывает, ClassA может претендовать на сбор мусора. Если вы видите ошибку, сообщите мне об этом, и я сделаю это. –
Вы можете смело позволить экземплярам класса A выходить за рамки без каких-либо изменений, которые мы видели в вашем коде, хранящемся в нем через экземпляры делегата. Однако в вашем коде, если вы хотите, чтобы экземпляр B выпал из области видимости, он не будет собран, потому что есть делегат, указывающий на метод 'ClassA_Processed', который хранится в списке вызовов' OnProcessed' в вашем экземпляре класс A – spender