You can use the following methods I wrote to check against existing event subscription. There are some overloads for more or less accurate subscription check.
Note: This only works with instance events and instance event subscription. If the event is subscribed or provided through a static method, this code can't help you since there is no subscriber or/and provider instance to check against.
using System;
using System.Linq;
using System.Reflection;
namespace AnyNamespace
{
    /// <summary>
    /// Provides extension methods for object types
    /// </summary>
    public static class ObjectExtender
    {
        /// <summary>
        /// Checks if an event subscription for potential subscriber 
        /// and its subscription method definition exists
        /// </summary>
        /// <param name="eventOwnerInstance">
        /// The object containing the subscriptions
        /// </param>
        /// <param name="eventOwnerType">
        /// The type which defines the event
        /// </param>
        /// <param name="eventName">
        /// The name of the event on the type which defines it
        /// </param>
        /// <param name="potentialSubscriber">
        /// The potential subscriber to check
        /// </param>
        /// <param name="subscriptionMethodInfo">
        /// The subscription method definition to use as search filter
        /// </param>
        /// <returns>
        /// <c>True</c> if the <c>potentialSubscriber</c> has at least one 
        /// subscription with the given <c>subscriptionMethodInfo</c>
        /// </returns>
        static public bool EventSubscriptionExists(this object eventOwnerInstance, 
            Type eventOwnerType, 
                string eventName, 
                    object potentialSubscriber, 
                        MethodInfo
subscriptionMethodInfo)
        {
            return EventSubscriptionExists(eventOwnerType, 
                eventOwnerInstance, 
                    eventName, 
                        potentialSubscriber, 
                            null, 
                               
subscriptionMethodInfo);
        }
        /// <summary>
        /// Checks if an event subscription for potential subscriber 
        /// and its subscription method name definition exists
        /// </summary>
        /// <param name="eventOwnerInstance">
        /// The object containing the subscriptions
        /// </param>
        /// <param name="eventOwnerType">
        /// The type which defines the event
        /// </param>
        /// <param name="eventName">
        /// The name of the event on the type which defines it
        /// </param>
        /// <param name="potentialSubscriber">
        /// The potential subscriber to check
        /// </param>
        /// <param name="subscriptionMethodName">
        /// The subscription method name to use as search filter
        /// </param>
        /// <returns>
        /// <c>True</c> if the <c>potentialSubscriber</c> has at least 
        /// one subscription with the given <c>subscriptionMethodName</c>
        /// </returns>
        /// <remarks>
        /// This is a more weak form of method overload 
        /// (object, Type, string, object, MethodInfo) 
        /// since it just uses a method name instead a method definition 
        /// to filter the subscriptions
        /// </remarks>
        static public bool EventSubscriptionExists(this object eventOwnerInstance, 
            Type eventOwnerType, 
                string eventName, 
                    object potentialSubscriber, 
                        string subscriptionMethodName)
        {
            return EventSubscriptionExists(eventOwnerType, 
                eventOwnerInstance, 
                    eventName, 
                        potentialSubscriber, 
                           
subscriptionMethodName, null);
        }
        /// <summary>
        /// Checks if an event subscription for potential subscriber exists
        /// </summary>
        /// <param name="eventOwnerInstance">
        /// The object containing the subscriptions
        /// </param>
        /// <param name="eventOwnerType">
        /// The type which defines the event
        /// </param>
        /// <param name="eventName">
        /// The name of the event on the type which defines it
        /// </param>
        /// <param name="potentialSubscriber">
        /// The potential subscriber to check
        /// </param>
        /// <returns>
        /// <c>True</c> if the <c>potentialSubscriber</c> has 
        /// at least one subscription
        /// </returns>
        static public bool EventSubscriptionExists(this object eventOwnerInstance, 
            Type eventOwnerType, 
                string eventName, 
                    object potentialSubscriber)
        {
            return EventSubscriptionExists(eventOwnerType, 
                eventOwnerInstance, 
                    eventName, 
                        potentialSubscriber, 
                            null,
                                null);
        }
        static bool
EventSubscriptionExists(Type eventOwnerType, 
            object eventOwnerInstance, 
                string eventName, 
                    object potentialSubscriber, 
                        string subscriptionMethodName, 
                            MethodInfo
subscriptionMethodInfo)
        {
            bool ret = false;
            var ownerType = eventOwnerType;
            if (ownerType.GetEvents().FirstOrDefault(x => x.Name ==
eventName) 
                is EventInfo eventInfo)
            {
                var fieldInfoFromEvent = ownerType.GetField(eventInfo.Name,
                                   
BindingFlags.NonPublic
                                        |
BindingFlags.Instance
                                            |
BindingFlags.GetField);
                var valueFromField = fieldInfoFromEvent.GetValue(eventOwnerInstance);
                if (valueFromField is Delegate eventDelegate)
                {
                    ret =
eventDelegate.GetInvocationList()
                        .Any(x =>
(potentialSubscriber == null 
                            || potentialSubscriber.Equals(x.Target))
                                &&
(subscriptionMethodName == null 
                                    ||
x.Method.Name == subscriptionMethodName)
                                       
&& (subscriptionMethodInfo == null 
                                            || subscriptionMethodInfo.Equals(x.Method)));
                }
                // else:
there are no subscribers at all
            }
            // else: no
event with given name exists (consider to throw an exception here)
            return ret;
        }
    }
}
Here is a demo how it works:
using System;
namespace AnyNamespace
{
    class EventProvider
   
{
       
public event EventHandler Event;
   
}
    class EventConsumer
   
{
       
private void EventCatcher(object sender, EventArgs e)
       
{
            // foo
            ;
        }
       
public void SubscribeIfNotIsAlready(EventProvider
eventProvider)
       
{
            // less
accurate check
           
if
(eventProvider.EventSubscriptionExists(eventProvider.GetType(), 
                nameof(EventProvider.Event),
this))
            {
          
     Console.WriteLine("The eventConsumer has
subscribed to the eventProvider, "
                    + "we don't know with which method,
but a subscription exists ...");
           
}
           
// more
accurate check
           
if (eventProvider.EventSubscriptionExists(eventProvider.GetType(),
                nameof(EventProvider.Event), this, nameof(EventCatcher)))
           
{
                Console.WriteLine("The eventConsumer has
even subscribed to the eventProvider "
                    + "with a method named
'EventCatcher', so we don't need to do it again ...");
           
}
            else
            {
                Console.WriteLine("There was no subscription
by 'EventCatcher' for this event, " 
                    +"we add now ..");
                eventProvider.Event +=
EventCatcher;
           
}
        }
    }
    class Program
   
{
       
static EventProvider eventProvider = new EventProvider();
       
static EventConsumer eventConsumer = new EventConsumer();
       
static void Main(string[] args)
       
{
           
Console.WriteLine("1. Imagine this code is not known by us and it conditionally
"
                + "adds a subscription to an
event.");
           
eventConsumer.SubscribeIfNotIsAlready(eventProvider);
            Console.WriteLine("2. Now we continue
without knowning if we still need to add "
                + "a subscription to the specified
event.");
           
DoSomething();
           
Console.ReadKey();
       
}
       
static void DoSomething()
        {
           
/* assume,
that we don't know if the event is already subscribed:
             * maybe, because the class is
partial or, or, or whyever
             */
           
eventConsumer.SubscribeIfNotIsAlready(eventProvider);
        }
    }
}
 
No comments:
Post a Comment