Search code examples
c#abstract-classderived-class

Please explain the outcome of Shape r = new Square() and why Square's methods aren't available


I'm working through Jeff Fritz's c# tutorial videos, and there is some code like this that uses an abstract class:

public abstract class Shape {}
public class Rectangle : Shape {}
public class Square : Rectangle {
    public string SquareOnlyMethod() { return "I am a square"; }
}


public static void Main()
{
    Square s = new Square(); 
    
    Console.WriteLine(s.GetType());            // Square
    Console.WriteLine(s is Shape);             // True
    Console.WriteLine(s is Rectangle);         // True
    Console.WriteLine(s is Square);            // True
    Console.WriteLine(s.SquareOnlyMethod());   // I am a square
    
    Shape r = new Square();
    
    Console.WriteLine(r.GetType());            // Square
    Console.WriteLine(r is Shape);             // True
    Console.WriteLine(r is Rectangle);         // True
    Console.WriteLine(r is Square);            // True
    Console.WriteLine(r.SquareOnlyMethod());   // 'Shape' does not contain a definition for 'SquareOnlyMethod' and no extension method 'SquareOnlyMethod' accepting a first argument of type 'Shape' could be found
}

Can somebody please explain the following?

  1. What is actually created when we do Shape r = new Square();? Is it a Shape or a Square?
  2. Why does GetType return Square but then the method cannot be found that is within the Square class?

Jeff says (if I understand correctly) that, "'Shape` is created with the footprint of Square", but then moves on.

Fiddle


Solution

  • The problem you are seeing starts with the following line Shape r = new Square(); because even though you are creating a Square but using the base type. I am assuming the concept Jeff is trying to show you is Polymorphism which can be check here with a better example of the shapes problem https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/polymorphism.

    In the Microsoft example you see that the base class provides common functionality for any derive class (shape) to leverage, extend, or override. So you can potentially treat a single array of different Shape children as Shapes and access or call methods (virtual for overriding) across any child shape (hence many forms).

    var shapes = new List<Shape>
    {
        new Rectangle(),
        new Triangle(),
        new Circle()
    };
    
    // Polymorphism at work #2: the virtual method Draw is
    // invoked on each of the derived classes, not the base class.
    foreach (var shape in shapes)
    {
        shape.Draw();
    }