Действительно ли необходимо явно удалить обработчики событий в C#

Вы получили, что тип свойства был классом (который, честно говоря, почти все в .NET было бы, включая String), но сначала вам нужно отразить этот тип и перечислить его свойства, как (базовый пример; делает некоторые допущения и элиды обработки ошибок для краткости):

static object GetPropertyValue(object parent, string nestedPropertyName)
{
    object propertyValue = null;

    var tokens = nestedPropertyName.Split('.');
    foreach (var token in tokens)
    {
      var property = parent.GetType().GetProperty(token, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
      propertyValue = property.GetValue(parent);

      if (propertyValue is null) return null;
      parent = propertyValue;
    }

    return propertyValue;
}
115
задан Kiquenet 15 January 2019 в 15:15
поделиться

2 ответа

В Вашем случае все прекрасно. Это - объект, который публикует события, который сохраняет цели из обработчиков событий живым. Таким образом, если я имею:

publisher.SomeEvent += target.DoSomething;

затем publisher имеет ссылку на target, но не наоборот.

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

хитрый случай - когда издатель долговечен, но подписчики не хотят быть - в [1 112], что случай необходимо отказаться от подписки обработчики. Например, предположите, что у Вас есть некоторый сервис передачи данных, который позволяет Вам подписаться на асинхронные уведомления об изменениях пропускной способности, и объект службы передачи долговечен. Если мы делаем это:

BandwidthUI ui = new BandwidthUI();
transferService.BandwidthChanged += ui.HandleBandwidthChange;
// Suppose this blocks until the transfer is complete
transferService.Transfer(source, destination);
// We now have to unsusbcribe from the event
transferService.BandwidthChanged -= ui.HandleBandwidthChange;

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

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

РЕДАКТИРОВАНИЕ: Это должно ответить на комментарий Jonathan Dickinson. Во-первых, посмотрите на документы для Делегат. Равняется (возражают) , которые ясно дают поведение равенства.

, Во-вторых, вот короткая, но полная программа для показа работы неподписки:

using System;

public class Publisher
{
    public event EventHandler Foo;

    public void RaiseFoo()
    {
        Console.WriteLine("Raising Foo");
        EventHandler handler = Foo;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
        else
        {
            Console.WriteLine("No handlers");
        }
    }
}

public class Subscriber
{
    public void FooHandler(object sender, EventArgs e)
    {
        Console.WriteLine("Subscriber.FooHandler()");
    }
}

public class Test
{
    static void Main()
    {
         Publisher publisher = new Publisher();
         Subscriber subscriber = new Subscriber();
         publisher.Foo += subscriber.FooHandler;
         publisher.RaiseFoo();
         publisher.Foo -= subscriber.FooHandler;
         publisher.RaiseFoo();
    }
}

Результаты:

Raising Foo
Subscriber.FooHandler()
Raising Foo
No handlers

(Протестированный на Моно и.NET 3.5SP1.)

Дальнейшее редактирование:

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

using System;

public class Publisher
{
    ~Publisher()
    {
        Console.WriteLine("~Publisher");
        Console.WriteLine("Foo==null ? {0}", Foo == null);
    }

    public event EventHandler Foo;
}

public class Subscriber
{
    ~Subscriber()
    {
        Console.WriteLine("~Subscriber");
    }

    public void FooHandler(object sender, EventArgs e) {}
}

public class Test
{
    static void Main()
    {
         Publisher publisher = new Publisher();
         Subscriber subscriber = new Subscriber();
         publisher.Foo += subscriber.FooHandler;

         Console.WriteLine("No more refs to publisher, "
             + "but subscriber is alive");
         GC.Collect();
         GC.WaitForPendingFinalizers();         

         Console.WriteLine("End of Main method. Subscriber is about to "
             + "become eligible for collection");
         GC.KeepAlive(subscriber);
    }
}

Результаты (в.NET 3.5SP1; Моно, кажется, ведет себя немного странно здесь. Изучит то некоторое время):

No more refs to publisher, but subscriber is alive
~Publisher
Foo==null ? False
End of Main method. Subscriber is about to become eligible for collection
~Subscriber
179
ответ дан Jon Skeet 24 November 2019 в 02:26
поделиться

В Вашем случае Вы в порядке. Я первоначально считал Ваш вопрос назад, что подписчик выходил из объема, не издатель . Если издатель события выходит из объема, то эти ссылки подписчику (не подписчик самого, конечно!) идут с ним и нет никакой потребности явно удалить их.

Мой исходный ответ ниже, о том, что происходит, если Вы создаете подписчика события и позволяете ему выйти из объема без отмены подписки. Это не относится к Вашему вопросу, но я оставлю его на месте для истории.

, Если класс все еще регистрируется через обработчики событий, то это все еще достижимо. Это - все еще живой объект. GC после графика события найдет, что соединился. Да, Вы захотите явно удалить обработчики событий.

Просто, потому что объект вне объема его исходного выделения, не означает, что это - кандидат на GC. Пока живая ссылка остается, это живо.

7
ответ дан Eddie 24 November 2019 в 02:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: