Опубликован: 14.12.2009 | Уровень: для всех | Доступ: платный
Лекция 3:

Методы класса

< Лекция 2 || Лекция 3: 123 || Лекция 4 >

Ошибки в задании типов параметров

Представьте, что когда вы впервые изучали сложение чисел, учитель неожиданно задал вам такую задачу: "Сложите число 5 и цветок ".

Как бы вы поступили? Наверное, ответили бы, что цветок — это не число, и выполнить сложение невозможно. Правильно.

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

Строительный блок: Параметры
Чтобы в методе выбиралось нужное значение, необходимо указать соответствующие параметры.

Каждый раз при вызове метода мы должны убедиться, что подставляем правильный тип значений в параметры. В приведенном примере мы подставляем два целых числа, так как параметры метода "LuckyNumber" были определены как целые числа.

class Person
{
  // Поля
  string firstName;
  string lastName;
  // Метод
  public void LuckyNumber(
  int numberOfTeeth, int age)
  {
    Console.WriteLine("Счастливое число" + numberOfTeeth * age);
  }
}

Person Petr;
Petr = new Person();
Petr.LuckyNumber(24, 14);
Примечание редактора. Внимательный читатель спросит: "Складывая строку с числом при вызове метода Console.WriteLine, не делаем ли мы ту же ошибку, как в случае сложения цветка с числом?". Здесь мы полагаемся на то, что компьютер (точнее, компилятор языка C#) умеет справляться с этим – сначала он автоматически преобразовывает число в строку и только потом выполняет операцию сложения — сцепление строк.

Приводимые до сих пор методы были void-методами. Они выводили некий текст на экран и затем возвращались назад к месту их вызова, как бы говоря: "Свое дело я сделал и вернулся в исходную точку". Однако иногда необходимо вернуть некоторое значение в точку вызова метода. В этих случаях следует написать метод, который будет возвращать значение, отличное от void.

Приведем пример. Напишем метод, который будет выполнять поиск количества конечностей указанного животного и затем отправлять полученное число туда, откуда этот метод был вызван.

Следует помнить, что с помощью метода мы показываем компьютеру, КАК выполнять определенное действие. Сначала я напишу то, чего хочу добиться от него, на русском языке, а затем на C#:

  • если животное, о котором мы говорим, — слон, то number of legs = 4 ;
  • иначе, если животное, о котором мы говорим, — индейка, то number of legs = 2 ;
  • иначе, если животное, о котором мы говорим, — устрица, то number of legs = 1 ;
  • иначе, если мы говорим о каких-либо других животных, то number of legs = 0.
int NumberOfLegs(string animalName)
{
    if (animalName == "слон") //Если название животного — слон
    {
        // Возвращаемое значение 4
        return 4;
    }
    else if (animalName == "индейка") //Иначе, если животное — индейка
    {
        // Возвращаемое значение 2
        return 2;
    }
    else if (animalName == "устрица")//Иначе, если животное — устрица
    {
        // Возвращаемое значение 1
        return 1;
    }
    else //Иначе (при всех других условиях)
    {
        // Возвращаемое значение 0
        return 0;
    }
}

Теперь мы можем вызвать метод. Давайте сделаем это дважды:

int i;
    //Переменная "i" будет хранить значение числа конечностей.
i = NumberOfLegs("индейка");
    //Теперь i = 2, получив значение, возвращенное методом NumberOfLegs
Console.WriteLine("У индейки конечностей – " + i);
i = NumberOfLegs("обезьяна");
    //Теперь i = 0. Догадайтесь, почему!
Console.WriteLine("У обезьяны конечностей – " + i);

На экран будут выведены тексты: "У индейки конечностей — 2" и "У обезьяны конечностей — 0". Итак, метод возвращает значение, которое можно принять в точке его вызова.

Мы определили метод именно так:

int NumberOfLegs(string animalName)
{
...
}

А не так:

void NumberOfLegs(string animalName)
{
...
}

И не так:

string NumberOfLegs(string animalName)
{
...
}

Дело в том, что нам необходимо, чтобы в данном случае метод возвращал целое число — не "пустое" значение ( void ), не строку букв, а именно целое число. А для работы с целыми числами используется тип данных Integer, или int в сокращенном варианте.

При написании метода мы всегда указываем тип данных, возвращаемых этим методом. Если возвращать значение не надо, используется void – для возврата пустого значения.

void JustWriteSomething(string someThing)
{
  Console.WriteLine(someThing);
}

И наконец: возможно, вы догадались, что слово return возвращает значение. Когда компьютер встречает это слово, происходит выход из метода и возврат запрашиваемого значения.

Строительный блок: Возвращаемые значения
Иногда необходимо получить значение из метода. В таком случае вместо указания типа void, сообщающего, что "никакого значения возвращено не будет", мы указываем определенный тип данных, возвращаемых методом.

Возвращаемые значения автоматически становятся доступными в любом месте, где мы вызываем метод.

Например, используя возвращенное значение, мы могли бы сначала сохранить ответ в переменной части выражения и затем использовать значение переменной в отдельном выражении.

Или мы могли бы вызвать метод непосредственно в выражении WriteLine.

class Person
{
  // Поля
  string firstName;
  string lastName;
  // Метод
  int LuckyNumber(int numberOfTeeth,
  int age)
  {
  return (numberOfTeeth * age);
  }
}
Person Anna;
Anna = new Person();
int num = Anna.LuckyNumber(24, 14);
Console.WriteLine("Счастливое число
Анны:" + num);


Console.WriteLine("Счастливое число
Анны:" + Anna.LuckyNumber(24, 14));

Доступ к методам, аналогично доступу к полям класса, регулируется с помощью ключевых слов. По умолчанию все методы будут рассматриваться как private (закрытые), то есть они применяются только внутри своего класса. Чтобы разрешить их использование для других классов, можно добавить слово public в начало объявления метода.

public void JustWriteSomething(string someThing)
{
    Console.WriteLine(someThing);
}

В реальном мире людям запрещается входить в некоторые помещения без специального разрешения. Например, в ресторанах только повара и официанты могут проходить на кухню – это закрытая зона. В то же время обеденный зал предназначен для свободного доступа, и в нем могут находиться любые лица. Подобным же образом некоторый код закрыт для других классов.

Мы уже рассматривали пример с закрытыми и открытыми полями. Дополним его: введем закрытые ( private ) и открытые ( public ) методы в класс Animal и затем пытаемся обратиться к ним из класса.

class Animal
{
    //Поля
    public string kindOfAnimal;
    public string name;
    public int numberOfLegs;
    public int height;
    public int length;
    public string color;
    bool hasTail;
    protected bool isMammal;
    private bool spellingCorrect;
    //Методы
    // Открытый метод, получающий информацию о том, чем питается животное
    public string GetFoodInfo()
    {
    // Представим, что здесь расположен код, выполняющий поиск по базе данных
    …
    }
    
    // Закрытый метод для проверки правильности написания вида животного
    private void SpellingCorrect()
    {
    // Представим, что здесь расположен код для проверки правописания
    …
    }
    
    // Защищенный метод, определяет существование данного вида животного
    protected bool IsValidAnimalType()
    {
    //код для проверки существующих видов животных
    …
    }
}

class Zoo
{
    Animal a = new Animal ();
    a.name = "Kangaroo";
    string food;
    bool animalExists;
    
    // Следующий код будет выполнен успешно, поскольку классу "Zoo" разрешено
    // обращаться к открытым методам в классе "Animal"
    food = a.GetFoodInfo(); // Вызов открытого метода
    
    // Обе следующие строки НЕ будут выполнены, поскольку классу "Zoo"
    // не разрешено обращаться к закрытым или защищенным методам
    a.spellingCorrect(); // Попытка вызова закрытого метода
    animalExists = a.IsValidAnimalType(); // Попытка вызова защищенного метода
}

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

Примечание редактора. Классов без конструктора не бывает, поскольку объект класса можно создать только путем вызова конструктора класса. Даже если программист не добавит в класс конструктор, это будет сделано по умолчанию, но параметров такой конструктор не имеет. Полезно иметь в классе конструктор с параметрами, роль которых уже пояснялась. Подобных конструкторов может быть несколько.
class Person
{
  // Поля
  string firstName;
  string lastName;
  // Метод-конструктор для класса Person
  public Person()
  {
    firstName = "Johnny";
    lastName = "Rocket";
  }
}

Метод-конструктор вызывается по-особому: при каждом создании экземпляра класса с помощью конструкции new.

Напоминание:

Под "экземпляром класса" мы понимаем определенный объект класса. Например, в одном из предыдущих разделов мы выделили "Гориллу Джереми" как определенный объект, или экземпляр класса Animal.

Итак, если мы выполним следующий код:

Person p = new Person();
Console.WriteLine(p.lastName);

то в результате на экране появится слово "Rocket". Написав конструкцию new Person(), мы тем самым дали указание компьютеру вызвать конструктор класса Person для создания нового объекта этого класса. Он будет связан с переменной p, у которой задано значение "Rocket" для поля lastName.

Приведем аналогичный пример из реальной жизни. В некоторых странах новорожденного регистрируют, согласно закону, еще в родильном доме, чтобы он как можно скорее стал членом общества и получил все гражданские права.


Это действие можно сравнить с методом-конструктором, выполняемым для класса. Прежде чем новый экземпляр класса сможет что-либо сделать, выполняется метод-конструктор. В него можно включить любые планируемые к выполнению действия, прежде чем объект будет считаться "готовым к жизни".

Конструкторы с параметрами

В конструктор можно включить параметры. Приведем пример класса с двумя различными конструкторами:

class Person
{
  // Поля
  string firstName;
  string lastName;
  // Первый метод-конструктор
  public Person()
  {
    firstName = "Johnny";
    lastName = "Rocket";
  }
  // Второй метод-конструктор
  public Person(string f, string l)
  {
    this.firstName = f;
    this.lastName = l;
  }
}

Таким образом, мы получили два разных способа конструирования объекта. Например, этот:

Person p = new Person();

В таком случае в поле p.lastName будет автоматически подставлено значение "Rocket". Или этот:

Person p = new Person("Petr", "Ivanov");

Тогда в поле p.lastName будет подставлено значение "Ivanov".

Слово this относится к объекту, который мы создаем, то есть фактически указывается: "подставлять в поле имени и фамилии этого объекта любые значения, передаваемые методу-конструктору".

Примечание редактора. В данном случае слово this можно добавить и в первый конструктор – для уточнения имени полей. Ничего не изменится, если во втором конструкторе имена полей будут указываться без this. Но иногда такое уточнение необходимо. Например, если во втором конструкторе имя параметра задавать не одной буквой f, а именем firstName, отражающим суть параметра, то без уточнения this в имени поля не обойтись, иначе компьютер запутается, не понимая, где имя поля, а где имя параметра метода.
< Лекция 2 || Лекция 3: 123 || Лекция 4 >
Алексей Фролов
Алексей Фролов
Кристина Горбунова
Кристина Горбунова
Анатолий Федоров
Анатолий Федоров
Россия, Москва, Московский государственный университет им. М. В. Ломоносова, 1989