Home > Software engineering >  C# cannot access properties
C# cannot access properties

Time:01-27

I am practising inheritance in c#, I have a class called Animal, a sub-class called Bird, and a sub-class called Parrot.

Parrot inherits from Bird, and Bird inherits from Animal.

When I instantiate a new object Animal animal = new Parrot(); I can't access the existing properties in Bird and Parrot classes, I can only access the properties of Animal class.

Animal.cs

internal class Animal
{
    private int id;

    public int Id { get => id; set => id = value; }
}

Bird.cs

internal class Bird: Animal
{
    private int flyingSpeed;

    public int FlyingSpeed { get => flyingSpeed; set => flyingSpeed = value; }
}

Parrot.cs

internal class Parrot: Bird
{
    private string color;

    public string Color { get => color; set => color = value; }
}

CodePudding user response:

If you make a new object like this:

Animal animal = new Parrot();

You're explicitly declaring it as an Animal. So when you use it, you're limited to the properties of Animal. However, it's unlikely you would make a declaration like that. Sometimes you will, but usually not. It's more likely that you would use the base class as a property or a method in a case where you don't care what the actual type is, for example:

class Person {
    public string Name { get; set; }
    public Animal Pet { get; set; }
}

In that case, you don't really care what kind of animal it is and you can assign any kind of animal to it:

var person = new Person {
    Name = "Gabriel",
    Pet = new Parrot();
}

That said, if for some reason you need to access the properties of the subtype, and have prior knowledge that it is actually a Parrot, then you can cast it and access the properties of Parrot:

((Parrot) animal).FlyingSpeed

If you don't have that prior knowledge, but you want to find out, you can use pattern matching:

if (animal is Parrot parrot) {
    Console.WriteLine(parrot.FlyingSpeed);
}

More reading: Inheritance in C# and .NET

CodePudding user response:

I can only access the properties of Animal class.

Of course, because realistically if you're in a situation where you want to treat everything as an Animal it means you can "get by" with just using those things that are common to all animals

If you wanted you can ask c# to check if the thing inside your Animal typed variable is a Parrot, and if it is you can cast it to a Parrot and use Parrot based things on it..

..but this is breaking the whole beauty of what polymorphism brings us

Let's have a different example.

You have a Shape as a parent class, and you have subclasses of Rectangle and Triangle. Shape might have some properties that are common to all shapes in your drawing program: FillColor, LineColor, Position, Width etc. Rectangle might have a WidthToHeight ratio specific to itself only. Triangle might have a Type (scalene, isosceles etc) specific to itself only

Shape also specifies some method DrawYourselfOnThis(Canvas c) - the method is abstract, so it doesn't have any code inside it at the Shape level, but any class that derived from Shape must provide some implementing code that draws that shape on the provided canvas

The user creates a list of shapes, choosing Rectangle or Triangle and setting properties.. The various rectangles and triangles are stored in an array of Shape

When time comes to draw them all, the program can just create a canvas and enumerate the array, saying over and over again "Draw yourself on this" and passing the canvas into the method. The rendering engine doesn't care what the true shape is inside the Shape object in the array; all it wants to do is call DrawYourself.. and because that method is declared at Shape level it can be guaranteed to exist on a Shape. Rectangle's version of DrawYourself uses the props on a rectangle (some coming from shape level and some coming from rectangle) to draw a rectangle. Triangles version draws a triangle, and the code will be slightly different

Ultimately, all the correct shapes are drawn and the renderer never needed to know what they were because it only wanted to use the things it could see on a Shape


Another example, closer to home; suppose you're writing a pet shop app and your shopping cart is an array of Animal. Every animal has a price, so Price is a property of Animal. A fish's constructor sets the price to $1. A cat's constructor sets the price to $20. You can put any number of any variety of fish and cats into your basket (whether the fish will make it to the check out..) and critically the shopkeeper doesn't need to know what they are in order to work out how much to bill you; they just loop over the animal array, treating everything as just an Animal with a Price and adding the sums up. If the shop keeper is going

foreach(Animal a in basket)
  if(a is Fish)
    total  = 1;
 else if(a is Cat)
    total  = 20;

then things have gone wrong. Adding up the prices of the animals can be done using just the info that is available at animal level; it doesn't need the shopkeeper to know what a fish is and what it costs. If it was done like this then the shopkeeper needs to know the specifics of everything in the basket and can only handle types known at the time the shopkeeper is created. Picture a scenario where your friend writes a plug-in for your program that adds a whole load of new animals; if you use the "it's an Animal, it has a Price, regardless of what it is" approach then the shopkeeper can add those animals up too, even though they were never even a part of the original program.


If you have a parent class but you're thinking "I need to know what kind of child is inside this parent so that I can make the code behave properly" something has gone wrong with your object modelling; that code you're writing in place X is probably in the wrong place

  •  Tags:  
  • Related