"Полиморфическое свойство, рассчитывающее..."

Рейтинг: 0Ответов: 2Опубликовано: 07.09.2014

Здравствуйте. Мучают в универе C#...
Была лабораторная работа, несколько классов, описывающих геометрические фигуры, реализуют некий интерфейс с методом Square(), который возвращает площадь фигуры. А вот задание из следующей лабораторной:

Для задания предыдущей лабораторной работы во всех классах конкретных фигур метод расчёта их площади заменить полиморфическим свойством, рассчитывающим площадь.

Я правильно понимаю, что задание сформулированно не совсем корректно, и правильнее было сказать

...свойством, содержащем (хранящем) значение площади.

Ну, по типу Length массива. А рассчитывать эту самую площадь можно, например, в конструкторе.

Или в шарпе есть какие-то особые свойства, которые умеют считать?

Ответы

▲ 6Принят

Если вы знакомы с ООП и его стандартной терминологией, то, вероятно, должны быть в курсе, что поле и свойство - это разные понятия, внешне выглядящие схожим образом. Вы в своем вопросе, очевидно, свойством называете то, что в ООП зовется полем. Однако же свойство - это кое-что другое. Свойство - это по сути синтаксический сахар над методом (или парой методов) для возврата некоего значения. Конкретнее:

class Person
{
    // это поле. Не свойство 
    private int _someField;

    // а вот это уже свойство
    public int Age {get; set; }
}

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

class Person
{
    //  то же самое поле, ничего нового
    private int _someField;

    // весь код, описанный ниже
    // представляет  собой то,
    // во что раскрывается свойство
    private int age;

    public int get_age() 
    {
        return age;
    }

    public int set_age() 
    {
        return age;
    }
}

Для чего это нужно? Можно же обойтись обычным полем и не морочить себе голову. Оказывается, нужно. Поле - это просто "кусок" данных, или даже "внутренности" класса, и конечный пользователь может сделать с этими "внутренностями" что угодно, только дай ему волю. Например, если это поле будет представляеть собой возраст человека, то конечный пользователь может запросто сделать этот возраст отрицательным, или очень большим, что способно сломать внутреннюю логику программы. Поэтому поле удобнее было бы обернуть в какую-то логику, которая позволит ограничить буйство пользователя (под пользователем здесь подразумевается программист, который будет работать с этим классом). Например:

class Person
{                
    private int _age;

    public int Age 
    {
        get { return _age; }
        set 
        {
            if(value <= 0 || value > 120)
                throw new SomeException("A terrible exception was thrown!");
        }
    }
}

Уже более надежно - пользователь не может поломать логику, связанную с возрастом. То же самое можно было бы сделать, имея приватное поле _age и пару публичных методов GetAge и SetAge, но так выглядит элегантнее (создается впечатлнение, что Age - это по-прежнему поле) и тратится меньше кода. Плюс вы всегда можете сделать публичным только геттер или только сеттер, чего в случае с полем сделать нельзя.

Теперь касательно вашего вопроса - свойство, возвращающее площадь фигуры, как раз должно представлять собой нечто вроде

// вариант для прямоугольника
public override double Square 
{
    get 
    {
        return _width * _height;
    }
}

где _width и _height - поля, в которых хранятся длина и ширина соответственно. Вычислять же площадь в конструкторе - не слишком хорошая идея - конструктору и без этого есть чем заняться, тем более, что если размеры вашей фигуры будут меняться в течение жизни объекта, то это и вовсе бесполезно.

З.Ы. Кстати, маленький забавный то ли баг, то ли фича языка: Следующий, казалось бы вполне правильный код, не будет скомпилирован:

public class Foo
{
    public int Prop { get; set; }  // ошибка

    public int get_Prop()
    {
        return 10;
    }
}

В строке, помеченной комментарием, компилятор сообщит вам, что метод get_Prop уже был объявлен. Это происходит, очевидно, оттого, что свойство Prop компилятор раскладывает на пару методов get_Prop и set_Prop (плюс соответствующее поле)

▲ 1

@Dazar, в шарпе на уровне языка реализованы аксессоры - сеттеры и геттеры. Можно объявить свойство, которое при доступе к нему само будет рассчитывать значение:

public int width;
public int height;
public int space {
    get {
        return width * height;
    }
}

http://msdn.microsoft.com/ru-ru/library/aa287786(v=vs.71).aspx

(конкретно в данном примере, конечно, нет гарантий переполнения или того, что width и height будут заданы в момент получения space)