471,317 Members | 1,402 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,317 software developers and data experts.

How to Design Delegate Architecture ?

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

--
Joanna Carter [TeamB]
Consultant Software Engineer
Jan 26 '06 #1
4 1330
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");
}
}
Jan 26 '06 #2
"Marc Gravell" <mg******@rm.com> a écrit dans le message de news:
e8**************@TK2MSFTNGP12.phx.gbl...

| 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

--
Joanna Carter [TeamB]
Consultant Software Engineer
Jan 26 '06 #3

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 .

Jan 26 '06 #4

"Joanna Carter [TeamB]" wrote:
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.

<snip>
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.
Jan 26 '06 #5

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

reply views Thread by Andy Read | last post: by
2 posts views Thread by Matthius | last post: by
2 posts views Thread by SemSem | last post: by
reply views Thread by Joerg Rech | last post: by
19 posts views Thread by neelsmail | last post: by
2 posts views Thread by Tem | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.