Класс WeakDelegate, предоставляющий возможность создания "слабых" делегатов - C#
Формулировка задачи:
Помогите пожалуйста решить задачку!) При добавлении делегата
объект source сохраняет ссылку на объект target через экземпляр делегата.
Соответственно, объект target не сможет быть освобожден GC, если на объект source сохранились ссылки даже если других ссылок на target нет.
Задача: требуется разработать класс WeakDelegate, предоставляющий возможность создания "слабых" делегатов, которые позволяют GC освободить target, если на target нет обычных ссылок (например, через обычные делегаты).
Класс WeakDelegаtе должен содержать метод Create с обычным делегатом в качестве параметра, возвращающий "слабый" делегат такого же типа, что и переданный (шаблон Proxy). Если target был освобожден GC, то "слабый делегат" ничего не выполняет (при необходимости возвращает значение или значения по умолчанию). Требуется поддержка делегатов с произвольным числом параметров, с переменным числом параметров, с ref и out параметрами, с возвращаемым значением.
Пример:
source.ShitHappened += new EventHandler<ShitHappenedEventArgs>(target.Method);
source.ShitHappened += (EventHandler<ShitHappenedEventArgs>)WeakDelegate.Create(new EventHandler<ShitHappenedEventArgs>(target.Method));
Решение задачи: «Класс WeakDelegate, предоставляющий возможность создания "слабых" делегатов»
textual
Листинг программы
public class WeakDelegate<TDelegate> where TDelegate : class { class MethodTarget { public readonly WeakReference Reference; public readonly MethodInfo Method; public MethodTarget (Delegate d) { Reference = new WeakReference (d.Target); Method = d.Method; } } List<MethodTarget> _targets = new List<MethodTarget>(); public WeakDelegate() { if (!typeof (TDelegate).IsSubclassOf (typeof (Delegate))) throw new InvalidOperationException ("TDelegate must be a delegate type"); } public void Combine (TDelegate target) { if (target == null) return; foreach (Delegate d in (target as Delegate).GetInvocationList()) _targets.Add (new MethodTarget (d)); } public void Remove (TDelegate target) { if (target == null) return; foreach (Delegate d in (target as Delegate).GetInvocationList()) { MethodTarget mt = _targets.Find (w => d.Target.Equals (w.Reference.Target) && d.Method.MethodHandle.Equals (w.Method.MethodHandle)); if (mt != null) _targets.Remove (mt); } } public TDelegate Target { get { var deadRefs = new List<MethodTarget>(); Delegate combinedTarget = null; foreach (MethodTarget mt in _targets.ToArray()) { WeakReference target = mt.Reference; if (target != null && target.IsAlive) { var newDelegate = Delegate.CreateDelegate ( typeof (TDelegate), mt.Reference.Target, mt.Method); combinedTarget = Delegate.Combine (combinedTarget, newDelegate); } else deadRefs.Add (mt); } foreach (MethodTarget mt in deadRefs) // Remove dead references _targets.Remove (mt); // from _targets. return combinedTarget as TDelegate; } set { _targets.Clear(); Combine (value); } } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д