Looking for c# Keywords? Try Ask4Keywords

C# Language Слабые ссылки


пример

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

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

Простое использование:

WeakReference reference = new WeakReference(new object(), false);

GC.Collect();

object target = reference.Target;
if (target != null)
  DoSomething(target);

Таким образом, слабые ссылки могут использоваться для поддержания, например, кеша объектов. Однако важно помнить, что всегда существует риск того, что сборщик мусора доберется до объекта, пока не будет восстановлена ​​сильная ссылка.

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

Предположим, что у нас есть обработчик события на источнике:

Source.Event += new EventHandler(Handler)

Этот код регистрирует обработчик событий и создает сильную ссылку от источника события на объект прослушивания. Если исходный объект имеет более длительный срок службы, чем слушатель, и слушателю больше не нужно это событие, когда нет других ссылок на него, использование обычных событий .NET вызывает утечку памяти: исходный объект содержит объекты-слушатели в памяти, которые должен быть собран мусор.

В этом случае может быть хорошей идеей использовать шаблон слабых событий .

Что-то вроде:

public static class WeakEventManager
    {
    public static void SetHandler<S, TArgs>(
    Action<EventHandler<TArgs>> add,
    Action<EventHandler<TArgs>> remove,
    S subscriber,
    Action<S, TArgs> action)
    where TArgs : EventArgs
    where S : class
        {
            var subscrWeakRef = new WeakReference(subscriber);
            EventHandler<TArgs> handler = null;

            handler = (s, e) =>
            {
                var subscrStrongRef = subscrWeakRef.Target as S;
                if (subscrStrongRef != null)
                {
                    action(subscrStrongRef, e);
                }
                else
                {
                    remove(handler);
                    handler = null;
                }
            };

            add(handler);
        }
    }

и используется так:

 EventSource s = new EventSource();
 Subscriber subscriber = new Subscriber();
 WeakEventManager.SetHandler<Subscriber, SomeEventArgs>(a => s.Event += a, r => s.Event -= r, subscriber, (s,e) => { s.HandleEvent(e); });

В этом случае, конечно, мы имеем некоторые ограничения - событие должно быть

public event EventHandler<SomeEventArgs> Event;

Как MSDN предлагает:

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