I have access to a class structure, which I cannot modify, as follows:
Graphics
Circle
Line
etc.
Again, I cannot modify it! These all have individual properties such as Radius, FirstPoint, LastPoint, etc., as well as some common properties.
I want to create a method that accepts a Graphics object, and depending on the type of object, will run a ToJson method:
Graphics g = db.GetGraphic(123);
// Console.WriteLine(g.GetType()) prints "Circle"
// Should run some specific implementation for `Circle` type graphics, and
// have an overload for all types including Graphics
ToJson(g);
At first I imagined I could craftily overload the ToJson method:
ToJson(Graphics g) { ... }
ToJson(Circle g) { ... }
ToJson(Line g) { ... }
however this of course goes for the generic ToJson(Graphics) overload each time.
I'm sure I could do something like the following:
if (g is Circle) ...
if (g is Line) ...
if (g is Graphics) ...
or create a Dictionary to reduce the complexity for each type, but that doesn't feel like the best way of doing things
What I've considered
I've considered if there's some generic wrapper method I could use around each object (e.g., new JsonGraphics(g).ToJson()), but I do not want to have to perform any manual type checking myself.
I have looked at the double dispatch and visitor pattern, but I wasn't sure they met my requirements as they look like I have to modify these classes (or maybe I just didn't fully understand them), and (kinda obvious, however) generics are also basically out of the window as they require me to know in advance what type of Graphics object this is.
Two questions then:
Is there a better way to do this other than to use some Dictionary or something other if (g is Type)-like?
If I could modify the classes, how would the pattern look? This isn't possible in this case, but is double dispatch/visitor the best way to go in the case I could?
Without being able to modify the base class, or have access to the concrete type before it's turned into a generic
Graphicstype, unfortunately I don't think there's anything you can do except inspect the runtime type of theGraphicsobject.You can use a switch statement (since C# 7.0), which is slightly cleaner than your
ifchain:Personally I don't see much advantage in using a Dictionary over a switch statement like this - both can be put away into a little self-contained method (and so reduce the amount of violation of the open/close principle), but the switch will be significantly cheaper.
You can also use
dynamic, which causes the runtime to do late binding:... although, dynamic has a fairly large runtime cost, and is generally considered smell.