WeakReference - я делаю это правильно? - PullRequest
1 голос
/ 22 февраля 2012

У меня есть статический класс, который выставляет событие:

public static class MyStaticClass
{
    static bool myBool= false;
    public static bool MyBool
    {
        get { return myBool; }
        private set
        {
            myBool= value;

            var handler = MyBoolChanged;
            if (handler != null)
                handler(null, null);
        }
    }

    public static event EventHandler MyBoolChanged;
}

А потом я регистрируюсь на нем, используя этот шаблон:

class AnotherClass
{    
    WeakReference _me;

    public MyMethodInAnotherClass()
    {
        _me = new WeakReference(this);
        MyStaticClass.MyBoolChanged+= 
                (_me.Target as AnotherClass).MyMethodInAnotherClassCallback;    
    }

    private void MyMethodInAnotherClassCallback(some arguments)
    {
    }
}

Я хочу добиться, чтобы MyStaticClass выполнял обработчик только в том случае, если экземпляр AnotherClass не был удален (и не был отменен из регистрации).

1 Ответ

2 голосов
/ 22 февраля 2012

Лучший способ использовать это - забыть о событии и использовать вместо него какой-то список;скажем List<WeakReference>;тогда вы можете получить:

interface IFoo {
    void Bar(some args);
}

с:

static class Whatever {
    private static readonly List<WeakReference> items=new List<WeakReference>();
    public static void Add(IFoo foo) {
        if(foo != null) {
            var newRef = new WeakReference(foo);
            lock(items) { items.Add(newRef); }
        }
    }
    public static void DoIt(some args) {
        lock(items) {
           foreach(var item in items) {
              IFoo foo = item.IsAlive ? item.Target as IFoo : null;
              if(foo != null) foo.Bar(some args);
           }
        }
    }
}

с дополнительными механизмами для удаления определенного IFoo и удаления всех мертвых foos, оставленных todo.

Тогдавам просто нужен AnotherClass : IFoo с реализацией Bar(), которая применяет ваш обратный вызов.

Дополнительный акцент: статические коллекции (включая события) довольно опасны;Вы должны время от времени проводить какую-то проверку, чтобы удалить пустые элементы, и попытаться отменить подписку, где это возможно (например, в Dispose()).Как иллюстрация:

public static void Remove(IFoo foo) {
    lock (items) { // also remove any dead debris
        items.RemoveAll(x => !x.IsAlive || x.Target == foo || x.Target == null);
    }
}
...