Question

Given:

interface I
{
}

class B: I
{
}

class C: I
{
}

class A
{

    public void Method(B arg)
    {
    }

    public void Method(C arg)
    {
    }

    public void Method(I arg)
    {
       // THIS is the method I want to simplify.
       if (I is B)
       {
          this.Method(arg as B);
       }
       else if (I is C)
       {
          this.Method(arg as C);
       }
    }
}

I know that there are better ways to design this type of interactions, but because of details which would take too long to explain this is not possible. Since this pattern will be duplicated MANY times, I would like to replace the conditional logic with a generic implementation which I could use just one line. I can't see a simple way to implement this generic method/class, but my instincts tell me it should be possible.

Any help would be appreciated.

Was it helpful?

Solution

What you want is double dispatch, and visitor pattern in particular.

OTHER TIPS

I would put the method inside the interface and then let polymorphism decide which method to call

interface I
{
   void Method();
}

class B : I
{
   public void Method() { /* previously A.Method(B) */}
}

class C : I
{
   public void Method() { /* previously A.Method(C) */ }
}

class A
{
   public void Method(I obj)
   { 
     obj.Method();
   }
}

Now when you need to add a new class, you only need to implement I.Method. You don't need to touch A.Method.

This is kinda ugly but it gets the job done:

public void Method(B arg)
{
  if (arg == null) return;
...
}
public void Method(C arg)
{
  if (arg == null) return;
...
}

public void Method(I arg)
{
  this.Method(arg as B);
  this.Method(arg as C);
}

I don't think I would do it this way, though. It actually hurts looking at that. I'm sorry I forced you all to look at this as well.

interface I
{ 
} 

class B : I
{
}

class C : I
{
}    

class A 
{
    public void Method(B arg)
    {
        Console.WriteLine("I'm in B");
    }

    public void Method(C arg)
    {
        Console.WriteLine("I'm in C");
    }

    public void Method(I arg)
    {
        Type type = arg.GetType();

        MethodInfo method = typeof(A).GetMethod("Method", new Type[] { type });
        method.Invoke(this, new I[] { arg });
    }
}

It doesn't exist in a convenient form withing C# - see here for an idea based on F#'s pattern matching, that does exactly what you want. You can do some things with reflection to select the overload at runtime, but that will be very slow, and has severe issues if anything satisfies both overloads. If you had a return value you could use the conditional operator;

return (I is B) ? Method((B)I) : ((I is C) ? Method((C)I) : 0);

Again - not pretty.

Easy. In Visual Basic I do this all the time using CallByName.

Sub MethodBase(value as Object)
    CallByName(Me, "RealMethod", CallType.Method, value)

This will call the overload of RealMethod that most closely matches the runtime type of value.

I'm sure you can use CallByName from C# by importing Microsoft.VisualBasic.Interaction or by creating your own version using reflection.

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