ГЛАВНАЯ     АРХИВ     НАПИСАТЬ АДМИНУ     ПОДПИСАТЬСЯ НА RSS     ВОЙТИ      

Поиск

Категории

Облако тегов

  << Предыдущий пост       Следующий пост >>  
От: ironMan
12. августа 2011 02:37

Подмена методов с помощью ключевого слова new замечательно работает, если у вас есть ссылка на производный объект. А что будет, если у вас есть ссылка, приведенная к базовому классу, но нужно, чтобы компилятор вызывал реализацию метода из производного класса ? Это именно тот момент, когда в дело вступает полиморфизм. Полиморфизм позволяет вам многократно определять методы в иерархии классов так, что в период выполнения в зависимости от того, какой именно объект используется, вызывается соответствующая версия данного
метода.

Обратимся к нашему примеру с сотрудником. Приложение PolylApp работает корректно, поскольку у нас есть два объекта: Employee и SalariedEmployee. В более практичном приложении мы, вероятно, считывали бы все записи о сотрудниках из БД и заполняли ими массив. Хотя некоторые сотрудники работают по контракту, а другим выплачивается зарплата, все они должны быть помещены в массив в виде объектов одного типа — базового класса Employee. Но при циклической обработке массива, когда происходит получение каждого объекта и вызов его метода CalculatePay, нам бы хотелось, чтобы компилятор вызывал подходящую реализацию метода CalculatePay.

В следующем примере добавлен новый класс — ContractEmployee. Главный класс приложения теперь содержит массив объектов типа Employee и два дополнительных метода: LoadEmployees, загружающий объекты «сотрудник» в массив, и DoPayroll, обрабатывающий массив, вызывая метод CalculatePay для каждого объекта.



using System;

class Employee
{
public Employee(string name)
{
this.Name = name;
}

protected string Name;
public string name
{
get
{
return this.Name;
}
}

public void CalculatePay()
{
Console.WriteLine ("Employee.CalculatePay вызвана для {0} ", name) ;
}
}

class ContractEmployee: Employee
{
public ContractEmployee(string name) : base(name)
{
}

public new void CalculatePay()
{
Console.WriteLine("ContractEmployee.CaiculatePay вызвана для {0} ", name!
}
}

class SalariedEmployee: Employee
{
public SalariedEmployee (string name) : base(name)
{
}

public new void CalculatePay()
{
Console.WriteLine("SalariedEmployee.CalculatePay вызвана для {0} ", name)
}
}

class Ро1у2Aрр
{
protected Employee[] employees;

public void LoadEmployees() /* эмулируем загрузку из базы данных */
{
employees = new Employee[2];
employees[0] = new ContractEmployee("Алексей Рубинов");
employees[l] = new SalariedEmployee("Василий Лазерко");
}

public void DoPayroll()
{
foreach(Employee emp in employees)
{
emp.CalculatePaу() ;
}
}

public static void Main()
{
Poly2App poly2 = new Poly2App();
poly2.LoadEmployees();
poly2.DoPayroll() ;
}
}



Однако, запустив это приложение (Ро1у2Арр), вы получите такую информацию:

Employee.CalculatePay вызвана для Алексей Рубинов
Employee.CalculatePay вызвана для Василий Лазерко

Ясно, что это совсем не то, что нам нужно: для каждого объекта вызывается реализация метода CalculatePay из базового класса. То, что здесь происходит, это — пример раннего связывания (early binding). Во время компиляции этого кода компилятор С#, изучив вызов emp.CalculatePay, определил адрес памяти, на который ему нужно перейти во время этого вызова. В таком случае это будет адрес метода Employee.CalculatePay. Вызов метода Employee.CalculatePay представляет собой проблему. Мы хотим, чтобы вместо раннего связывания происходило динамическое (позднее) связывание (late binding). Динамическое связывание означает, что компилятор не выбирает метод для исполнения до периода выполнения. Чтобы заставить компилятор выбрать правильную версию метода объекта, мы используем два новых ключевых слова: virtual и override. С методом базового класса применяется ключевое слово virtual, a override — с реализацией метода в производном классе. Вот еще один пример, который на этот раз работает должным образом,— РоlуЗАрр.



using System;

class Employee
{
public Employee(string name)
{
this.Name = name;
}

protected string Name;
public string name
{
get
{
return this.Name;
}
}

virtual public void CalculatePay()
{
Console.WriteLine("Employee.CalculatePay вызвана для {0}", name);
}
}

class ContractEmployee: Employee
{
public ContractEmployee(string name) : base(name)
{
}

override public void CalculatePay()
{
Console.WriteLine("ContractEmployee.CalculatePay вызвана для {0}", name);
}
}

class SalariedEmployee: Employee
{
public SalariedEmployee (string name) : base(name)
{
}

override public void CalculatePay()
{
Console.WriteLine("SalariedEmployee.CalculatePay вызвана для {0}", name);
}
}

class Poly3App
{
protected Employee[] employees;

public void LoadEmployees() /* эмулируем загрузку из базы данных */
{
employees = new Employee[2];
employees[0] = new ContractEmployee{"Алексей Рубинов")
employees[l] = new SslariedEmployee("Василий Лазерко")
}

public: void DoPayroll()
{
foreach(Employee emp in employees)
{
emp.CalculatePay();
}
}

public static void Main()
{
Poly3App poly3 = new Poly3App();
poiy3.LoadEmployees();
poly3.DoPayroll();
}
}



Выполнение такого кода приведет к следующим результатам:

ContractEmployee.CalculatePay вызвана для Алексей Рубинов
SalariedEmployee.CalculatePay вызвана для Василий Лазерко


( отрывок из книги В. В. Лабор "Си Шарп: Создание приложений для Windows" )

 

Похожие записи


Многопоточный HTTP сервер на C#
Оригинал статьи здесь: Многопоточный сервер на C# за 15 минут Автор (на хабре): ertaquo C# довольно простой и гибкий язык. Вместе с .NET поставляется довольно много уже готовых классов, что делает его еще проще. Настолько, что вполне можно написать простой многопоточный HTTP-сервер для отдачи статического содержимого всего за 15 минут. Можно было бы использовать уже...

Нейгел, Ивьен, Глинн, Уотсон, Скиннер - C# 2008 и платформа .NET 3.5
Название: C# 2008 и платформа .NET 3.5 для профессионалов Авторы: Нейгел, Ивьен, Глинн, Уотсон, Скиннер Издательство: Вильямс ISBN: 978-5-8459-1458-3 Год: 2008 Страниц: 1392 От издателя: Эта книга является совершенным руководством по языку C# 2008 и его среде. Она обновлена с учетом вышедших версий .NET 3.5 и Visual Studio 2008. Начиная с обзора и архитектуры ...

Виртуальные свойства в C#
Свойства, как и методы, могут быть перегружены в производных классах. Для свойств также могут задаваться модификаторы virtual, override или abstract. Подробно о наследовании говорилось в главе «Методы», сейчас я лишь хочу еще раз привести подробный пример использования механизма виртуализации с применением свойств: [code:c#] using System; enum COLORS { RE...

Добавить комментарий




biuquote
  • Комментарий
  • Предпросмотр
Loading


  Сохранить комментарий