c# - Double dispatch inside a single inheritance tree -


i have inheritance tree of different line-classes, starting abstract line-class. want able intersect each line each other line, , sometimes, not know neither of runtime types, e.g. i'm calling line.intersect(line) (so need double dispatch). call abstract overload of overriden intersect-methods, e.g. circle.intersect(line) instead of circle.intersect(actualtype). here's example code:

class program {   static void main(string[] args)   {     line straightline = new straightline();     line circle = new circle();      // print: "circle intersecting line."     // should print: "circle intersecting straight line."     circle.intersect(straightline);      console.readline();   } }   abstract class line {   public abstract void intersect(line line);    public abstract void intersect(straightline straightline);    public abstract void intersect(circle circle); }   class straightline : line {   public override void intersect(line line)   {     console.writeline("straigth line intersecting line.");   }    public override void intersect(straightline straightline)   {     console.writeline("straight line intersecting straight line.");   }    public override void intersect(circle circle)   {     console.writeline("straight line intersecting circle.");   } }   class circle : line {   public override void intersect(line line)   {     console.writeline("circle intersecting line.");   }    public override void intersect(circle circle)   {     console.writeline("circle intersecting circle.");   }    public override void intersect(straightline straightline)   {     console.writeline("circle intersecting straight line.");   } } 

one possible workaround use dynamic, do. however, want migrate .net standard-library, dynamic not allowed.

are there other ways make work? i'd willing switch abstract class 1 or multiple interfaces, if helps. maybe visitor-pattern applicable, although i've seen used different inheritance trees (and find quite ugly).

it possible emulate double dispatch using reflection. targeting .net standard 1.1 , using nuget-package system.reflection, intersect(line line)-method not need abstract or virtual, has implemented once.

this whole example code .net standard library (i return string instead of using console.writeline(), since latter not available in .net standard):

using system.reflection;  namespace intersectlibrary {   public abstract class line   {     public string intersect(line line)     {       var method = this.gettype().getruntimemethod(nameof(intersect), new[] { line.gettype() });       return (string)method.invoke(this, new[] { line });     }      public abstract string intersect(straightline straightline);      public abstract string intersect(circle circle);   }     public class straightline : circle   {     public override string intersect(straightline straightline)     {       return "straight line intersecting straight line.";     }      public override string intersect(circle circle)     {       return "straight line intersecting circle.";     }   }     public class circle : line   {     public override string intersect(circle circle)     {       return "circle intersecting circle.";     }      public override string intersect(straightline straightline)     {       return "circle intersecting straight line.";     }   } } 

please note when targeting .net framework, system.reflection offers different methods, , code need modified.

in console application, following happen:

using system; using intersectlibrary;  namespace consoleapplication {   class program   {     static void main(string[] args)     {       line straightline = new straightline();       line circle = new circle();       circle circle2 = new circle();        // calls "line.intersect(line)", , correctly       // prints "circle intersecting straight line.".       console.writeline(circle.intersect(straightline));        // calls "line.intersect(line)",       // since argument's compile-time type "line".       console.writeline(circle2.intersect(straightline));        // calls "line.intersect(circle)",       // since argument's compile-time type "circle".       // @ runtime, call resolved       // "straightline.intersect(circle)" via single dispatch.       console.writeline(straightline.intersect(circle2));        console.readline();     }   } } 

if have 1 object of compile-time type line , 1 of concrete type (e.g. circle), it's better call line.intersect(circle), since won't need (slower) reflection resolve method call. however, circle.intersect(line) work, , importantly, calling line.intersect(line) possible.


Comments

Popular posts from this blog

Command prompt result in label. Python 2.7 -

javascript - How do I use URL parameters to change link href on page? -

amazon web services - AWS Route53 Trying To Get Site To Resolve To www -