2

I have the following. It works. I want to do it in a way that avoids using dynamic and avoids having the code grow as O(n^2) in the number of types. The standard double dispatch solution I am aware of has O(n) code in each of the types A, B, C, D, leading to overall O(n^2).

Is there a sane way to do that?

  public class P {}
  public class A: P {}
  public class B: P {}
  public class C: P {}
  public class D: P {}
  public class DynamicDispatchLowPriorityMethods
  {
    // The superclass is to avoid a runtime error when calling Multi(b, a).
    // Without something like this, the call is ambiguous.
    protected string _Output {get;set;}
    public DynamicDispatchLowPriorityMethods()
    {
    }
    public void Multi(P x, P y) {
      _Output += "PP ";
    }
    public void Multi(B x, P y) {
      _Output += "bP ";
    }
  }
  [TestFixture()]
  public class DynamicDispatch: DynamicDispatchLowPriorityMethods
  {
    public void Multi(A x, A y) {
      _Output += "aa ";
    }
    public void Multi(A x, P y) {
      _Output += "aP ";
    }
    public void Multi(P x, A y) {
      _Output += "Pa ";
    }
    public void Multi(B x, B y) {
      _Output += "bb ";
    }
    public void Multi(C x, C y) {
      _Output += "cc ";
    }
    public void Multi(D x, D y) {
      _Output += "dd ";
    }
    public void Multi(B x, D y) {
      _Output += "bd ";
    }
    public void DynamicMulti(P x, P y) {
      this.Multi((dynamic)x, (dynamic)y);
    }
    [Test()]
    public void TestDynamicDispatch()
    {
      _Output = "";
      P a = new A ();
      P b = new B ();
      P c = new C ();
      P d = new D ();
      this.DynamicMulti(a, a);
      this.DynamicMulti(a, b);
      this.DynamicMulti(a, c);
      this.DynamicMulti(a, d);
      _Output += "\n";
      this.DynamicMulti(b, a);
      this.DynamicMulti(b, b);
      this.DynamicMulti(b, c);
      this.DynamicMulti(b, d);
      _Output += "\n";
      this.DynamicMulti(c, a);
      this.DynamicMulti(c, b);
      this.DynamicMulti(c, c);
      this.DynamicMulti(c, d);
      _Output += "\n";
      this.DynamicMulti(d, a);
      this.DynamicMulti(d, b);
      this.DynamicMulti(d, c);
      this.DynamicMulti(d, d);
      CommonDebug.WriteLine(_Output);
    }
  }

Output is:

  aa aP aP aP 
  Pa bb bP bd 
  Pa PP cc PP 
  Pa PP PP dd 

For background, see this question about alternatives to double dispatch.

Community
  • 1
  • 1
William Jockusch
  • 26,513
  • 49
  • 182
  • 323
  • Who knows how fast dynamic dispatch is with many types? Might well be O(n^2). A hash table based solution clearly is O(N). – usr Jul 27 '15 at 19:07
  • I'm assuming the actual operation being performed in the various `Multi()`s isn't as simple as string concatenation? If it were, you could put a virtual string property on `P`, like `Name`, and override it in each derived class, then just have a single `Multi()` function that takes two `P`s and concatenates their overriden `Name` properties... – Diosjenin Jul 27 '15 at 19:09
  • Okay, so what *is* happening inside the `Multi()`s? Because the way I see it, the properties of the `P` derivatives either need to interact in a type-specific way (int/float, int/double, int/DateTime, float/double, etc., etc.), in which case, ideal scenario, you're stuck writing something unique for each pair of types - or they can interact in a generic way, in which case you can override a property on the base class whose derived types can interact generically. – Diosjenin Jul 27 '15 at 19:30
  • Did give a thought to Expression Trees? You can have a `Dictionary` in which you can compile for the `value` the exact code you would call when calling either of those methods based on specific rules, and for the `key` you could retain all the possible calls to those methods. The compilation would be done only the first time as you'll have all those inside that `Dictionary` – alexo Jul 27 '15 at 19:49

0 Answers0