0

The title of the question may seem confusing but bear with me, I'll try to explain the problem as clearly as possible.

So I was just studying about the Liskov substitution principle from a course and the lecturer has given an example showing logical errors we can solve using this principle. Hence, the example shown below is the problem with the logical error.

(Note: Please read the whole question even if you don't know/find out this example has nothing to do with Liskov principle as I've mentioned that above. I've just kept this in question for reference, just in case someone bothers to answer that you're doing it the wrong way)

Rectangle is the parent class

class Rectangle
{
    public int Width { get; set; }
    public int Height { get; set; }

    public Rectangle()
    {
    }

    public Rectangle(int width, int height)
    {
        Width = width;
        Height = height;
    }

    public override string ToString()
    {
        return $"{nameof(Width)}: {Width}, {nameof(Height)}: {Height}";
    }
}

Square class

class Square : Rectangle
{
   public new int Width
   {
       set { base.Width = base.Height = value; }
   }

   public new int Height
   {
       set { base.Width = base.Height = value; }
   }
}

Just a simple Caller

private void Caller()
{       
     Rectangle rc = new Square(); //Upcasting here
     rc.Width = 4;
     Console.WriteLine($"{rc}"); //Now here the o/p is **Width: 4, Height: 0** which is correct

     //But when we use object initializer as shown below
     Rectangle rcTwo = new Square { Width = 4 };
     Console.WriteLine($"{rcTwo}"); //the o/p is **Width: 4, Height: 4**
}

Now aren't we just initializing the object in a different way? Why is the O/P supposed to differ in that case. I thought that object initializer is just an syntactical sugar when when we to create an object and initialize it's properties in comparison with the traditional approach.

TejasGondalia
  • 168
  • 3
  • 13
  • 1
    The difference is that the object initializer assigns the value before the cast (on a Square object), and the regular property set is happening after the cast (on a Rectangle object). The right hand side in the first case is fully evaluated before the assignment/cast happens. – Lennart Dec 29 '19 at 08:26

1 Answers1

1

You are right that it's syntactical sugar. But you have to think of the order of operations: assignment is done last, after all the operations on the right of the equals sign. So your second version with initialiser is the same as:

Square square = new Square();
square.Width = 4;
Rectangle rcTwo = square;
iakobski
  • 1,000
  • 7
  • 8
  • so is this what happens under the hood? – TejasGondalia Dec 29 '19 at 11:15
  • and also the solution that you proposed has nothing to do with the fact that Rectangle's ctor gets called first when we do Rectangle rcTwo = new Square { Width = 4 }; as Rectangle is the base class? – TejasGondalia Dec 29 '19 at 14:44
  • Yes that's right it does, but it also gets called first when you do `Square sq = new Square();` The base class constructor is always called when you create an object of a derived class, this has nothing to do with the upcasting. Your question is "which Width property is being called when it's in the object initialiser" and the answer is "the one belonging to the class that's being instantiated". – iakobski Dec 29 '19 at 15:57