Question

I have seen a few posts with answers on how to do this. The answers all relied on placing a Action within a dictionary essentially. The problem I have however is that I need to pass Actions with unknown signatures into a method, not within a dictionary.

I have existing code that uses the following method. I want to add a overload so I can maintain compatibility with the existing code.

    // Collection of notification observers.
    private static Dictionary<string, List<NotificationObserver>> _Observers = new Dictionary<string, List<NotificationObserver>>();
    public static SynchronizationContext Context { get; set; }

    public static void RegisterObserver(object observer, string notification, Action<object, Dictionary<string, object>> action)
    {
        // We only register valid objects.
        if (string.IsNullOrWhiteSpace(notification) || action == null || observer == null) return;

        // Create a new NotificationObserver object.
        // Currently you provide it a reference to the observer. This is not used anywhere; there are plans to use this.
        var registeredObserver = new NotificationObserver(observer, action);

        // Make sure the notification has already been registered.
        // If not, we add the notification to the dictionary, then add the observer.
        if (_Observers.ContainsKey(notification))
            _Observers[notification].Add(registeredObserver);
        else
        {
            var observerList = new List<NotificationObserver>();
            observerList.Add(registeredObserver);
            _Observers.Add(notification, observerList);
        }
    }

    public static void PostNotification(object sender, string notification, Dictionary<string, object> userData = null)
    {
        // Make sure the notification exists.
        if (_Observers.ContainsKey(notification))
        {
            // Loop through each objects in the collection and invoke their methods.
            foreach (NotificationObserver observer in _Observers[notification].Where(obs => obs != null))
            {
                if (Context == null)
                    observer.Action(sender, userData);
                else
                {
                    Context.Send((state) => observer.Action(sender, userData), null);
                }
            }

            // Clean ourself up.
            Task.Run(new Action(() =>
            {
                PurgeNullObservers();
            }));
        }
    }

Notification Observer

internal sealed class NotificationObserver
{
    internal NotificationObserver(object observer, Action<object, Dictionary<string, object>> action)
    {
        this.Observer = observer;
        this.Action = action;
    }

    internal object Observer { get; private set; }
    internal Action<object, Dictionary<string, object>> Action { get; private set; }

}

What I would like to do is the following within my codebase:

NotificationManager.RegisterObserver(this.SomeProperty, "SomeString", this.SomeProperty.DoStuff);
NotificationManager.RegisterObserver(this.Logger, "LogInfo", this.Logger.LogInfo);

Essentially, I want to provide support for 3rd party library objects that I don't have access to the source code and can't add methods that match my pre-determined Action signature. I also don't want 30 overloads for a ton of different signature variations.

Anyone know of a decent way of accomplishing this? If I have to modify my RegisterObserver and NotificationObserver I can, I was hoping to do it though without having to modify the existing method signature and just adding a overload.

Thanks in advance!

Was it helpful?

Solution

Why not just use a lambda expresssion when constructing the RegisterObserver call?

NotificationManager.RegisterObserver(this.ThirdParty, 
    "ThirdPartyData", 
    (i,j) => 
        {
             // call the third party method
             this.ThirdParty.ThirdPartyMethod(null, false, i);
             // other custom logic here using j (the action dictionary)
        });

As long as you have the information needed to 'adapt' the third party call to be compatible with your existing signature, you don't have a problem. You automatically capture all such information in the closure created by the lambda expression.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top