Как узнать, подписался ли кто-то на событие? - PullRequest
3 голосов
/ 10 сентября 2009

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

Пожалуйста, дайте мне знать, как мне этого добиться?

Ответы [ 4 ]

3 голосов
/ 10 сентября 2009

С Microsoft :

        // Wrap event invocations inside a protected virtual method
        // to allow derived classes to override the event invocation behavior
        protected virtual void OnRaiseCustomEvent(CustomEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<CustomEventArgs> handler = RaiseCustomEvent;

            // Event will be null if there are no subscribers
            if (handler != null)
            {
                // Format the string to send inside the CustomEventArgs parameter
                e.Message += String.Format(" at {0}", DateTime.Now.ToString());

                // Use the () operator to raise the event.
                handler(this, e);
            }
        }

Вы ищете if (handler! = Null) part. null , если нет подписчиков, not null , если есть подписчики.

1 голос
/ 10 сентября 2009

Образец класса Publisher предоставляет одно событие Publish. Метод IsRegistered запрашивает прикрепленные к событиям обработчики событий для данного экземпляра класса и возвращает значение true, если в этом экземпляре класса есть хотя бы один зарегистрированный / присоединенный обработчик событий. Переопределенный метод IsRegistered делает то же самое, но для статических типов.

Поместите этот код в проект консольного приложения и нажмите F5 для отладки, попробуйте.

internal class Publisher
{
    internal event EventHandler<EventArgs> Publish;

    internal bool IsRegistered(Type type)
    {
        if (Publish == null) return false;
        //
        return (from item in Publish.GetInvocationList() where item.Target == null & item.Method.DeclaringType == type select item).Count() > 0;

    }
    internal bool IsRegistered(object instance)
    {
        if (Publish == null) return false;
        //
        return (from item in Publish.GetInvocationList() where item.Target == instance select item).Count() > 0;
    }

    static int Main(string[] args)
    {
        Publisher p = new Publisher();
        //
        p.Publish += new EventHandler<EventArgs>(static_Publish);
        p.Publish += new EventHandler<EventArgs>(p.instance_Publish);            
        //
        Console.WriteLine("eventhandler static_Publish attach: {0}", p.IsRegistered(typeof(Program)));
        Console.WriteLine("eventhandler instance_Publish attach: {0}", p.IsRegistered(program));
        //
        return 0;
    }

    void instance_Publish(object sender, EventArgs e)
    {

    }
    static void static_Publish(object sender, EventArgs e)
    {

    }
}`
0 голосов
/ 10 сентября 2009

Есть два способа сделать это:

  1. Вы можете создать новую цепочку делегатов с удаленным отписавшимся делегатом и сравнить его с тем, который вы получили, прежде чем сохранить его. Если вы отмените подписку на делегата, у которого подписано , вы получите новую цепочку делегатов без этого делегата. В случае, если вы пытаетесь отписаться от делегата, у которого не подписан , вы получите ту же цепочку, что и у вас.
  2. Вы можете вручную пройтись по цепочке делегатов, чтобы увидеть, присутствует ли тот делегат, от которого вы хотите отказаться. Это можно сделать с помощью обычных методов Linq, таких как .Contains для простоты.

Первый случай может выглядеть как код ниже. Это создаст новую цепочку делегатов во временной переменной с делегатом, которого вы хотите удалить, удалить, а затем сравнить временную цепочку с существующей цепочкой. Если они одинаковы, делегат не присутствовал.

private EventHandler _Changed;
public event EventHandler Changed
{
    add
    {
        _Changed += value;
    }
    remove
    {
        EventHandler temp = _Changed - value;
        if (_Changed == null || temp == _Changed)
            throw new InvalidOperationException(
                "Delegate is not subscribed, cannot unsubscribe");
        _Changed = temp;
    }
}

Второй, как и код ниже, просто увидит, присутствует ли делегат, от которого вы хотите отказаться от подписки, в цепочке делегатов.

private EventHandler _Changed;
public event EventHandler Changed
{
    add
    {
        _Changed += value;
    }

    remove
    {
        if (_Changed == null || !_Changed.GetInvocationList().Contains(value))
            throw new InvalidOperationException(
                "Delegate is not subscribed, cannot unsubscribe");
        _Changed -= value;
    }
}

Обратите внимание, что вы можете, если хотите, использовать подобный код для обработки случая, когда делегат добавляется дважды.

0 голосов
/ 10 сентября 2009

в предположении среды pub / sub, просто вызовите provider.Unsubscribe (EventType, subscriber) и позвольте провайдеру определить, подписан подписчик или нет

...