Понятие об обновлении, наследовании и настройке свойства с использованием инициализатора объекта

Название вопроса может показаться запутанным, но потерпите меня, я постараюсь объяснить проблему как можно яснее.

Итак, я только что изучал принцип подстановки Лискова из курса, и лектор привел пример, показывающий логические ошибки, которые мы можем решить, используя этот принцип. Следовательно, пример, показанный ниже, является проблемой с логической ошибкой.

(Примечание: пожалуйста, прочитайте весь вопрос, даже если вы не знаете/обнаружите, что этот пример не имеет ничего общего с принципом Лискова, как я упоминал выше. Я просто оставил этот вопрос для справки, просто на случай, если кто-то потрудится ответить, что вы делаете это неправильно)

Rectangle является родительским классом

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}";
    }
}

Квадратный класс

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

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

Простой вызывающий абонент

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**
}

Разве мы не просто инициализируем объект по-другому? Почему O/P должен отличаться в этом случае. Я думал, что инициализатор объекта - это просто синтаксический сахар, когда мы создаем объект и инициализируем его свойства по сравнению с традиционным подходом.


person TejasGondalia    schedule 29.12.2019    source источник
comment
Разница в том, что инициализатор объекта присваивает значение до приведения (для объекта Square), а обычное задание свойства происходит после приведения (для объекта Rectangle). Правая сторона в первом случае полностью оценивается до того, как произойдет назначение/приведение.   -  person Lennart    schedule 29.12.2019


Ответы (1)


Вы правы, это синтаксический сахар. Но вы должны подумать о порядке операций: присваивание выполняется последним, после всех операций справа от знака равенства. Итак, ваша вторая версия с инициализатором такая же, как:

Square square = new Square();
square.Width = 4;
Rectangle rcTwo = square;
person iakobski    schedule 29.12.2019
comment
так это то, что происходит под капотом? - person TejasGondalia; 29.12.2019
comment
а также решение, которое вы предложили, не имеет ничего общего с тем фактом, что ctor Rectangle вызывается первым, когда мы делаем Rectangle rcTwo = new Square { Width = 4 }; поскольку Rectangle является базовым классом? - person TejasGondalia; 29.12.2019
comment
Да, это так, но он также вызывается первым, когда вы делаете Square sq = new Square(); Конструктор базового класса всегда вызывается, когда вы создаете объект производного класса, это не имеет ничего общего с повышением приведения. Ваш вопрос заключается в том, какое свойство Width вызывается, когда оно находится в инициализаторе объекта, а ответ принадлежит классу, экземпляр которого создается. - person iakobski; 29.12.2019