50105

Variable number of parameters

Question:

I'm improving an existing messaging system for my project, which should accept a variable number of parameters. Right now generics are used to pass arguments to the system. A lot of code repeats itself, so the question is - is it possible to merge all the versions of the class that take different number of parameters into a one single class? The whole messaging system I take as a foundation for mine can be found here: <a href="http://www.unifycommunity.com/wiki/index.php?title=CSharpMessenger" rel="nofollow">CSharpMessenger</a>

Code excerpts:

public delegate void Callback(); public delegate void Callback<T>(T arg1); public delegate void Callback<T, U>(T arg1, U arg2);

Version with no parameters:

static public class Messenger { private static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>(); static public void AddListener(string eventType, Callback handler) { if (!eventTable.ContainsKey(eventType)) { eventTable.Add(eventType, null); } // Add the handler to the event. eventTable[eventType] = (Callback)eventTable[eventType] + handler; } static public void Invoke(string eventType) { Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback callback = (Callback) d; if (callback != null) { callback(); } } } }

Version with one parameter:

static public class Messenger<T> { private static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>(); static public void AddListener(string eventType, Callback<T> handler) { if (!eventTable.ContainsKey(eventType)) { eventTable.Add(eventType, null); } // Add the handler to the event. eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler; } static public void Invoke(string eventType, T arg1) { Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback<T> callback = (Callback<T>) d; if (callback != null) { callback(arg1); } } } }

Version with two parameters:

static public class Messenger<T, U> { private static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>(); static public void AddListener(string eventType, Callback<T, U> handler) { if (!eventTable.ContainsKey(eventType)) { eventTable.Add(eventType, null); } // Add the handler to the event. eventTable[eventType] = (Callback<T, U>)eventTable[eventType] + handler; } static public void Invoke(string eventType, T arg1, U arg2) { Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback<T, U> callback = (Callback<T, U>) d; if (callback != null) { callback(arg1, arg2); } } } }

As you can see most of the code repeats itself, Is it possible to create some general version of the same class, that will take a variable number of parameters and to avoid repeating the same code so many times?

Thanks.

Answer1:

Callback parameters are normally passed in a subclass of EventArgs. There's already a simple generic delegate that abstracts this: EventHandler<TEventArgs> where TEventArgs : EventArgs. The variability in parameters can be added to subclasses of EventArgs.

So, if you can restructure your code to use these classes, you can have just one version. Something like this:

public static class Messenger<TEventArgs> where TEventArgs : EventArgs { private static Dictionary<string, EventHandler<TEventArgs>> eventTable = new Dictionary<string, EventHandler<TEventArgs>>(); public static void AddListener(string eventType, EventHandler<TEventArgs> handler) { if (eventTable.ContainsKey(eventType)) { eventTable[eventType] = eventTable[eventType] + handler; } else { eventTable.Add(eventType, handler); } } public static void Invoke(string eventType, TEventArgs args) { EventHandler<TEventArgs> d; if (eventTable.TryGetValue(eventType, out d)) { if (d != null) { d(args); } } } }

Recommend

  • How to create product of an array using values from sub-arrays
  • Haskell audio output on OS X?
  • Writing a dictionary to a CSV file [duplicate]
  • Using intent ACTION_SET_ALARM to allow application to set a UNIQUE alarm
  • StreamWriter not updating its path on new day
  • [TFS 2015]: Migrate users from one AD domain to another
  • Cannot create StorageItem in Outlook Add-In
  • Global results with Struts 2 and convention plugin
  • Haskell: Yesod and state
  • Implicit declaration of function 'sum' is invalid in C99
  • Monotouch - Issue with QLPreviewController
  • Turn off Zurb Foundation 5 meta tags
  • TFS Build notification options not populating build definitions
  • Swift 3 Custom extension of ns measurement? Ex. Sheeps to goats
  • Display Current Video in Windows Phone 8 using AudioVideoCaptureDevice?
  • Opaque reference instead of PImpl. Is it possible?
  • Set focus to first invalid form element in AngularJS
  • Find group of records that match multiple values
  • Build Successful but not running on simulator
  • how to save the state in userdefaults of accessory checkmark-iphone
  • MonoTouch: How to download pdf incrementally as indicated in the Apple slides “Building Newsstand Ap
  • Sails.js/waterline: Executing waterline queries in toJSON function of a model?
  • Redux, normalised entities and lodash merge
  • Eraser for UIBezierPath
  • Do create extension work in single-user mode in postgres?
  • Web-crawler for facebook in python
  • Getting 'uninitialized constant' error when using delegate in belongs_to in model
  • Akka Routing: Reply's send to router ends up as dead letters
  • Cannot Parse HTML Data Using Android / JSOUP
  • Suggestions to manage Login/Logout transitions
  • JTable with a ScrollPane misbehaving
  • Java static initializers and reflection
  • Exception on Android 4.0 `android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode)`
  • unknown Exception android
  • EntityFramework adding new object to nested object collection
  • Checking variable from a different class in C#
  • Observable and ngFor in Angular 2
  • failed to connect to specific WiFi in android programmatically
  • Unable to use reactive element in my shiny app
  • How can I use threading to 'tick' a timer to be accessed by other threads?