How to Design Delegate Architecture ?

  • Thread starter Joanna Carter [TeamB]
  • Start date
J

Joanna Carter [TeamB]

Hi folks

I think I have asked something similar before, but here goes again...

I have to call a method that varies depending on the type of one of its
parameters.

The object that I have to pass is of a base class.

I do not want to have an "if (...) else" construct if I can avoid it.

Example methods are :

void Method1(TextBoxBase widget)
{
}

void Method2(NumericUpDown widget)
{
}

Calling method looks like this :

void CallAppropriateMethod(Control widget)
{
...
}

I thought of adding the methods to a static class :

public static class WidgetHandler
{
public static void Method(TextBoxBase widget)
{
}

public static void Method(NumericUpDown widget)
{
}
}

....and calling them, hoping that the type would be inferred and called
appropriately.

void CallAppropriateMethod(Control widget)
{
WidgetHandler.Method(widget); // code this simple would be the best !!
}

But this, of course, involves casting a base type to a specific type; not
allowed :-((

I also thought of using delegates and retrieving a particular delegate based
on a type parameter, but I couldn't get a Dictionary<Type, MyDelegate> to
work as it meant having a return from the function that would be a "base"
delegate and that I could call without knowing the type of the parameter; so
far, no success.

Generic delegates don't seem to offer the answer as you have to know the
type of the delegate you want to invoke :-((

Am I really suffering from brain-fade on this one, or is there a method I
have simply not found yet ??

Joanna
 
M

Marc Gravell

Its not necessarily elegant, but you can do this with reflection in a
broadly acceptable way; I would prefer something neater, though:

using System;
using System.Reflection;
using System.Windows.Forms;

class Program {
private static void Main() {
WidgetHandler.CallAppropriateMethod(new TextBox());
WidgetHandler.CallAppropriateMethod(new NumericUpDown());
WidgetHandler.CallAppropriateMethod(new FlowLayoutPanel()); // don't
expect this to work
}
}

public sealed class WidgetHandler {

private WidgetHandler() { // private ctor
}
private static readonly WidgetHandler Singleton;
static WidgetHandler() {
Singleton = new WidgetHandler();
}

public static void CallAppropriateMethod(Control widget) {
if (widget == null)
throw new ArgumentNullException("widget");
Type widgetType = widget.GetType();
MethodInfo method = typeof(WidgetHandler).GetMethod("Method",
BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] {
widgetType }, null);

if (method == null)
throw new NotSupportedException("Method(" + widgetType.Name + ")
is not supported");
method.Invoke(null, new object[] { widget });
}

private static void Method(TextBoxBase widget) {
System.Diagnostics.Debug.WriteLine("I work with TextBoxBase
widgets");
}

private static void Method(NumericUpDown widget) {
System.Diagnostics.Debug.WriteLine("I work with NumericUpDown
widgets");
}
}
 
J

Joanna Carter [TeamB]

"Marc Gravell" <[email protected]> a écrit dans le message de (e-mail address removed)...

| Its not necessarily elegant, but you can do this with reflection in a
| broadly acceptable way; I would prefer something neater, though:

Well, as you say, it's not elegant, but it certainly does the job.

Like you, I really would prefer something better, but in the meanwhile your
solution allows me to get on with something else :)

Many thanks

Joanna
 
A

alantolan

Calling a different method based upon the type of the object sounds
like a good candidate for a polymorphic solution.
It would perhaps be tedious to implement but it will work and can be
extended.

Say you have 2 controls with which you want to do this

1) TextBox
2) Label


Define an interface IMyControl

public interface IMyControl
{
// Methods
void DoSomething();
}


Derive new versions of each control, implementing IMyControl

public class MyTextBox : System.Windows.Forms.TextBox, IMyControl {

...

public void DoSomething(){
// Do Something Textbox specific
}

}

public class MyLabel : System.Windows.Forms.Label, IMyControl {

...

public void DoSomething(){
// Do Something Label specific
}

}


Your selector now becomes


IControl iface;

try{

iface = (IControl) sender;
iface.DoSomething();

}
catch (System.InvalidCastException ex) {
throw new NotSupportedException("MESSAGE");
}
catch (System.Exception ex) {
// Handle exception or rethrow
}



PROS:
It is pretty easy to understand and can be extended to any number of
controls with no need of if..then or selection constructs.

CONS:
You need to generate custom versions of each control. (not that hard)
You need to replace all definitions/references to the base controls
with these new ones (can be tedious if one has an existing large
codebase)


NOTES:
If the functionality to be invoked is not accessible from within the
controls (e.g. on a form or in a separate class) then one can use a
callback setup, setting the target with static members on the derived
class


e.g.

...
public delegate void HandleSpecific();

public static void SetDelegate( HandleSpecific del) {
_handler = del;
}

private static HandleSpecific _handler;

public void DoSomething(){
_handler();
}


hth,
Alan .
 
L

Leslie Sanford

Joanna Carter said:
Hi folks

I think I have asked something similar before, but here goes again...

I have to call a method that varies depending on the type of one of
its
parameters.

The object that I have to pass is of a base class.

I do not want to have an "if (...) else" construct if I can avoid it.

Example methods are :

void Method1(TextBoxBase widget)
{
}

void Method2(NumericUpDown widget)
{
}

Calling method looks like this :

void CallAppropriateMethod(Control widget)
{
...
}

You need double dispatch for this. Unfortunately, C# doesn't have it.

You can use Visitor instead, but it requires adding an Accept method to
the visitees. If you're using control classes from the .NET framework,
this rules that out, unless you derive a class from each control class
you're using and add the Accept method there.

I also thought of using delegates and retrieving a particular delegate
based
on a type parameter, but I couldn't get a Dictionary<Type, MyDelegate>
to
work as it meant having a return from the function that would be a
"base"
delegate and that I could call without knowing the type of the
parameter; so
far, no success.

What I've done in a similar situation is to write a custom dispatcher
class. The class looks something like this:

public class TypeDispatcher
{
public void Dispatch(object obj)
{
if(obj is SomeType)
{
// Cast object to type and call a delegate
// or pass the casted object to a method of
// an object.
}
else if(obj is SomeOtherType)
{
// ...
}

// And so on...
}
}

You register delegates of a particular type for the object type you are
interested in. In other words, when the dispatcher finds the object's
type, it calls a preregistered delegate, passing it the object casted to
its type. You can use events instead. Or you can create interfaces for
each type and associate objects that implement the interfaces with the
dispatcher. The dispatcher will then pass along the casted object to the
interface's method for processing the object.

The nice thing about this approach is that you isolate the cascading
if/else if's to one location. It can be used any where you need
dispatching for the base type.

Hope this helps.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top