(извиняюсь, если это произошло раньше, я искал, но ничего не нашел для своих условий поиска)
Учитывая следующее:
void Method1 {
Foo _foo = new Foo();
_foo.DataReady += ProcessData();
_foo.StartProcessingData();
}
void ProcessData() { //do something }
StartProcessingData()
- это длинныйметод выполнения, который в конечном итоге ( и асинхронно ) вызывает событие DataReady
.(скажем, он выполняет вызов службы или что-то в этом роде)
Теперь _foo
раньше была переменной уровня класса, а событие раньше связывалось в конструкторе.
Однако, профилирование памяти показало, как это навсегда сохранит _foo
и все его зависимые элементы в памяти, поэтому я и изменил вышесказанное.
Мой вопрос: есть ли когда-нибудь случай, когда GC разрушит вещи?Method1
заканчивается быстро (и, конечно, до того, как событие произойдет), что означает, что _foo
перестает существовать.Однако означает ли это, что (поскольку _foo хранит ссылки на свои события) ProcessData()
никогда не сработает?Или, достаточно ли наличия события, чтобы _foo оставалось живым после окончания метода, достаточно, чтобы обеспечить запуск ProcessData?Или это неокончательно?
[В тестировании все работало нормально - всегда вызывается ProcessData
.Даже создание StartProcessingData
заняло много времени, а принудительное выполнение сбора GC (с помощью RedGate Memory Profiler) не удаляло его.Но я хотел бы быть уверен!]
Для уточнения: StartProcessingData()
возвращается немедленно.Объект Foo
будет выглядеть примерно так:
class Foo
{
SomeSerice _service;
event EventHandler<EventArgs> DataReady;
Foo()
{
_service = new SomeService();
_service.ServiceCallCompleted += _service_ServiceCallCompleted;
}
void StartProcessingData()
{
_service.ServiceCallAsync();
}
void _service_ServiceCallCompleted
{
DataReady(null,e);
}
Итак, что-то, что абстрагирует и эмулирует длительный асинхронный сервис, использующий события, чтобы сигнализировать о важных событиях.
Вот полный рабочий пример (консольное приложение)
class Program
{
static void Main(string[] args)
{
Class1 _class1 = new Class1();
Console.WriteLine("Disposing of Class 1");
_class1 = null;
GC.Collect();
System.Threading.Thread.Sleep(15000);
Console.Read();
}
}
internal class Class1
{
internal Class1()
{
Foo _foo = new Foo();
_foo.DataReady += new EventHandler<EventArgs>(_foo_DataReady);
_foo.StartProcessingData();
}
void _foo_DataReady(object sender, EventArgs e)
{
Console.WriteLine("Class 1 Processing Data");
}
}
class Foo
{
internal event EventHandler<EventArgs> DataReady = delegate { };
internal void StartProcessingData()
{
System.Threading.Timer _timer = new System.Threading.Timer(OnTimer);
Console.WriteLine("Firing event in 10 secs");
_timer.Change(10000, System.Threading.Timeout.Infinite);
}
private void OnTimer(object state)
{
DataReady(this, null);
}
}
Если вы запустите его, вы получите:
Firing event in 10 secs
Disposing of Class 1
Class 1 Processing Data