0

My demo code is below:


class Base
{

}

class SubA:Base
{
     private int propertyA;
     public int  PropertyA     
     {
          get{return propertyA}
      }
}

class SubB:Base
{
     private string propertyB;
     public string PropertyB     
     {
          get{return propertyB}
      }
}

class Program
{
     public void Action(Base obj)
     {
         //here i wanna use PropertyB if the ture obj is an instance of SubB.
         // use PropertyA if the true obj is an instance of SubA
     }
}

The true object I transfer to function "Action" is an instance of SubB or SubA. I wanna access the PropertyB(if SubB) or PropertyA(if SubA) in the "Action". Do I violate some basic OO rules? What is the best way to deal with such situation(I don't wanna use the C# key word As and Is to test the obj I transfered). I am totally confused now. Any advice or help is greatly appreciated.

Aiping He
  • 491
  • 1
  • 6
  • 10

2 Answers2

2

You can bypass the technical limitation easily by using type checks and casts (as and is in C#, as you've already seen), but this does indeed violate basic OO principles.

The problem is that you have defined that Action expects to receive Base as an argument, so that's the only information you should rely on. If an object of type Base does not expose the data you need it to expose, then you need to modify it. For instance you can add a "Property" property directly to base, and make it into some generic type, or into a base type that has two children, one supporting int values and the other string values. It might help if you might also consider why Action needs access to the data, and maybe delegate the usage of that data to Base and its children instead.

Oak
  • 26,231
  • 8
  • 93
  • 152
1

I think what you did was fine, however, you would probably need to find out the precise class name of obj by if (obj is SubA) {} else if (obj is SubB) {}.

From experience, the reason for creating a function like void Action(Base obj) is to process obj no matter what subclass of Base it may actually be. So by choosing obj to be of type Base means you're deciding not to do sub-type-specific processing inside the function.

I see that in the code above, the super class Base is only created to be able to pass a SubA or a SubB to Action, and in Action(Base obj), it seems like your only purpose is to process it depending on whether it's SubA or SubB. It makes more sense to have SubA and SubB to be separate classes NOT inheriting Base. Then, you should have a separate Action overload for each of SubA and SubB:

class Program
{
     public void Action(SubA obj)
     {
         // process exactly as SubA
     }

     public void Action(SubB obj)
     {
         // process exactly as SubB
     }
}

Other code in your program should be structured to know which of SubA or SubB is being worked on. You would instantiate a SubA or SubB depending on user input or a condition. For example:

protected void saveButton_onClick(Object sender, EventArgs e)
{
    if (User.IsInRole("Administrator"))
    {
         Action(new SubA());
    }
    else
    {
         Action(new SubB());
    }
}

The appropriate Action overload would be called. Let the logic of your program decide which class to instantiate. Avoid the need to "sniff" an object's actual type as much as possible.

Mickael Caruso
  • 8,721
  • 11
  • 40
  • 72