How to avoid "If a cascade" and type of casting using polymorphism?

Suppose the following class structure with a base class BC and 2 derived classes DC_A and DC_B; In addition, there is an XY class with the goo () method with a parameter of type BC and other methods

// base class public class BC { public virtual void foo(); } // derived class A public class DC_A : BC { public override void foo() {} } // derived class B public class DC_B : BC { public override void foo() {} } public class XY { public void goo(BC o) { // perfectly fine using polymorphism; no Ifs' no casting, OOP at its best ;-) o.foo(); // but what to do here? if ( (o as DC_A) != null ) { doX(o as DC_A); } else if ((o as DC_B) != null) { doY(o as DC_B); } } private void doX(DC_A o) {} private void doY(DC_B o) {} } 

Does it go around value objects using polymorphism, bad practice? 'a visitor template is offered;

The problem of the If cascade and casting is moved (not excluded) to the abstract base class.

Are there any better solutions to avoid if completely?

For me there is no way (in this example) to move functionality from doX / doY to the DC_A / DC_B class

Your advice is greatly appreciated.

Edit: The basis of this question is a C # / WinForms application with a form for managing a "test rule" consisting of differenct subsections, such as TestSpec, with a set of measurement types, test limits, etc. (My classes DC_A, DC_B) from EntityBase (= BC above) The form sends an event to the controller that changed the entity; simplified PropertyChanged (EntityBase o) The controller calls the corresponding method in the model class (the goo method in the XY class above), which is now responsible for executing business logic that not only stores the changed entity verification limit, but also, for example, creating a new limit verification object verification, increase verification specification specifications, etc. Maybe this way the general approach to a method like PropertiesChanged (EntityBase o) should be changed to more detailed events from the form and the specific event handler in the controller and model class for processing "TestLimitChanged", etc.

But this special case led me to the more general or "philosophical" question of polymorphism in general :-)

+4
source share
3 answers

If you are using .NET 4, there is a possibility with overloading and dynamic type, perhaps this is an alternative for you.

 class Program { static void Main(string[] args) { DC_A dca = new DC_A(); DC_B dcb = new DC_B(); XY xy = new XY(); xy.goo(dca); xy.goo(dcb); } } // base class public abstract class BC { public abstract void foo(); } // derived class A public class DC_A : BC { public override void foo() { } } // derived class B public class DC_B : BC { public override void foo() { } } public class XY { //public void goo<T>(T o) where T : BC //{ // //dynamic dyn = Convert.ChangeType(o, o.GetType()); // //dynamic dyn = o; // //gooi(dyn); // gooi((dynamic)o); //} // http://smellegantcode.wordpress.com/2008/11/04/dynamic-typing-in-c-4-and-duck-generics/ public void goo<T>(T o) where T : BC { gooi((dynamic)o); } private void gooi(DC_A o) { o.foo(); doX(o); } private void gooi(DC_B o) { o.foo(); doY(o); } private void gooi(BC o) { o.foo(); } private void doX(DC_A o) { } private void doY(DC_B o) { } } 
+5
source

My suggestion:

  • Provide your doX () and doY () methods so that they can be called from DC_A and DC_B implementations.
  • Add the abstract Do () method to BC.
  • Add Do () to DC_A to call the public doX () method.
  • Add Do () to DC_B to call the public doY () method.
  • Inside goo (), just call o.Do ().

You can separate everything further by passing the DC_A and DC_B they invoke to the delegate, instead of exposing doX () and doY (). It is very dependent on usage patterns.

However, this is very useful if you can add some value to the Do () implementation in derived classes. If all Do () does this simply by calling doX () or doY (), you are not getting any benefit from it.

So, I agree with another poster here that says it just does a casting.

+3
source

I don’t think there is too much to worry about once we fix a couple of things:

  • At the moment you are throwing more than you need
  • Only one of these if can be true, so you don't need else

After that we have:

  // perfectly fine using polymorphism; no Ifs' no casting, OOP at its best ;-) o.foo(); var dca = o as DC_A; if (dca != null) { doX(dca); } var dcb = o as DC_B; if (dcb != null) { doY(dcb); } 

which, I would say, looks good.

If you want to go further, you can change the doX and doY implementations to return immediately if they pass null ; then you could just say

 doX(o as DC_A); doY(o as DC_B); 
+2
source

All Articles