Questions
.pdfЗакомментируйте операторы == и !=. После этого скомпилируйте и запустите пример еще раз.
Введите одинаковые значения для полей p1.x, p2.x и p1.y, p2.y. Почему p1 != p2 несмотря на то, что p1.x == p2.x и p1.y == p2.y?Потому, что по умолчанию проверка операторами == и !=
проверяет условие указания операндов на один и разные объекты соответственно, а не равности значений их полей.
2. Когда Вы скомпилируете пример, вы увидите, что компилятор выдает предупреждение, которое говорит, что класс Point определяет операторы == и !=, но не переопределяет Object.Equals и Object.GetHashCode. Как Вы думаете, по какой причине это предупреждение, а не ошибка? Дело в том, что метод Equals() должен реализовывать ту же логику, что и оператор ==.
Закомментируйте оператор != в классе Point. Пересоберите приложение и объясните, что происходит и почему это происходит. Компилятор выдает ошибку о том, что оператор ==
переопределен, но требует также переопределить оператор !=.
3. Создайте новое консольное приложение с классом, который перегружает какие-либо операторы.
Постарайтесь придумать класс, полезный другим учащимся. Поделитесь вашей реализацией на форуме.
Пример:
using System;
class Program
{
public static void Main()
{
Random r = new Random();
int a_rows, a_collumns, b_rows, b_collumns;//размерности входных матриц Console.ForegroundColor = ConsoleColor.White;
for(;;)//while(true)
{
Console.WriteLine(
"\nПомните, что количество столбцов первой матрицы\n" + "должно совпадать с количеством строк второй матрицы!\n\n");
try
{
Console.WriteLine("\nВведите количество строк первой матрицы a:"); a_rows = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("\nВведите количество столбцов первой матрицы a:"); a_collumns = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("\nВведите количество строк второй матрицы b:"); b_rows = Convert.ToInt32(Console.ReadLine());
if (a_collumns != b_rows) continue;
Console.WriteLine("\nВведите количество столбцов второй матрицы b:"); b_collumns = Convert.ToInt32(Console.ReadLine());
break;
}
catch
{
Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\nИспользуйте только цифры!"); Console.ForegroundColor = ConsoleColor.White;
}
}
Matrix a = new Matrix(a_rows, a_collumns);//первая матрица Matrix b = new Matrix(b_rows, b_collumns);//вторая матрица Matrix c = new Matrix(a_rows, b_collumns);//третья матрица
//заполнение данными входных матриц for (int i = 0; i < a_rows; i++)
for (int j = 0; j < a_collumns; j++) a[i,j] = r.Next(100);
for (int i = 0; i < b_rows; i++)
for (int j = 0; j < b_collumns; j++) b[i,j] = r.Next(100);
Console.WriteLine(); a.Show();//отображаем первую матрицу b.Show();//отображаем вторую матрицу
c.Show();//отображаем результирующую матрицу
c = a * b;
Console.WriteLine("После переумножения матриц а и b матрица с:\n"); c.Show();//отображаем результирующую матрицу
}
}
class Matrix
{
int[,] array;//объявление массива (матрицы)
int rows, collumns;//количество строк и столбцов матрицы
public int Rows//количество строк
{
get { return rows; } set
{
if (value > 0) rows = value;
}
}
public int Collumns
{
get { return collumns; } set
{
if (value > 0) collumns = value;
}
}//количество столбцов
public int this[int i, int j]//индексатор
{
get { return array[i, j]; } set { array[i, j] = value; }
}
public Matrix(int countOfRows, int countOfCollumns)
{
Rows = countOfRows;
Collumns = countOfCollumns;
array = new int[Rows, Collumns];//создание массива (матрицы)
}
public void Show()
{
for (int i = 0; i < Rows; i++)
{
for (int j = 0; j < Collumns; j++)
{
Console.Write("{0,6}",array[i, j]);
}
Console.WriteLine();
}
Console.ReadLine();
}
public static Matrix operator *(Matrix a, Matrix b)
{
Matrix multy = new Matrix(a.Rows,b.Collumns); for (int i = 0; i < a.Rows; i++)
for (int k = 0; k < b.collumns; k ++ ) for (int j = 0; j < a.Collumns; j++)
multy[i, k] += a[i, j] * b[j, k]; return multy;
}
}
5.Предопределение методов. Свойства.
1.Что такое переопределение (overriding) методов? Приведите пример с двумя классами (первый класс – базовый, второй от него унаследован).
Виртуальным называется метод, объявленный с помощью ключевого слова virtual в базовом классе и переопределяемый в одном или нескольких производных классах. Таким образом, каждый производный класс может иметь собственную версию виртуального метода.
Пример:
class Animal
{
public virtual void Run()
{
return;
}
}
class Tiger: Animal
{
public int i;
public override void Run()
{
base.Method();
}
}
2. В чем ошибка в нижеприведенном коде? Исправьте код и объясните ошибку.
using System;
class SQLServerDb
{
// Bunch of other nonsalient members. public static void RepairDatabase()
{
Console.WriteLine("repairing database..."); Console.ReadLine();
}
}
class StaticMethod1App
{
public static void Main()
{
SQLServerDb classSQL = new SQLServerDb(); classSQL.RepairDatabase();
}
}
Ошибка заключается в вызове статического метода через объектную ссылку. Необходимо либо пометить метод как динамический (убрать из определения метода модификатор static), либо для его вызова использовать имя его класса, а не имя ссылки на объект этого класса.
using System;
class SQLServerDb
{
// Bunch of other nonsalient members. public void RepairDatabase()
{
Console.WriteLine("repairing database..."); Console.ReadLine();
}
public static void Main()
{
SQLServerDb classSQL = new SQLServerDb(); classSQL.RepairDatabase();
}
}
3. Могут ли виртуальные методы быть объявлены защищенными? Какие ключевые слова нужно писать в базовом и производном классе, чтобы реализовать виртуальный вызов?
Privat – не могут, protected - могут. Ключевые слова для реализации виртуального вызова:
сlass, virtual, :, override.
Теперь давайте обсудим вопросы, связанные со свойствами.
5. В каких случаях надо использовать не методы, а свойства?
Так как работа свойств подобна методам, возможно вообще обходится без использования свойств. Однако, они очень полезны и удобны в тех ситуациях, когда необходимо продолжение выполнения программы даже в случаях возникновения исключительных ситуаций, ведь свойства позволяют не допускать выполнение ошибочных действий, что приводят к возникновению исключений. Кроме того, с помощью свойств возможно ограничить область воздействия на определенные члены экземпляров объектов.
Однако свойства нельзя передавать методам посредством ref и out способом, а также свойства нельзя перегружать.
Что такое свойство только для чтения и свойство только для записи?
Это свойства, в которых определены лишь getили set-аксессоры. Соответственно, такие свойства позволяют либо считывать значение поля, либо устанавливать его.
Что такое функции для доступа (accessor functions)?
Средства доступа представляют собой функции, чьи задачи сводятся к доступу членам
(чаще закрытым) класса и выполнения определенных действий над ними. Get и Set – и есть функции доступа.. Аксессор подобен методу за исключением того, что в нем отсутствует объявление типа возвращаемого значения и параметров. В остальном, синтаксически очень схож с методом.
Какие еще есть способы использования свойств?
Еще свойства можно переопределять с использованием ключевых слов virtual и override.
6. Напишите программу, которая реализует два класса – Invoice и LineItem. Invoice должен содержать общедоступное поле – массив LineItem. Во время исполнения вы должны создать массив
LineItem и присвоить его в поле объекта Invoice. Добавьте в класс Invoice свойство Total, доступное только для чтения. Опубликуйте свое решение в форуме.
Пример: using System;
namespace Invoice
{
class Program
{
static void Main(string[] args)
{
Invoice invoice = new Invoice(); invoice.li = new LineItem[5];
}
}
class Invoice
{
public LineItem[] li; int total;
public int Total
{
get { return total; }
}
}
class LineItem
{
}
}
6. Интерфейсы. Атрибуты.
Сегодня мы рассмотрим такую важную тему как интерфейсы. Затем мы перейдем к продвинутым аспектам языка C# . Первый аспект, который мы рассмотрим - атрибуты и их использование.
Ну а пока - рассмотрим интерфейсы. Посмотрите на следующий код:
using System;
public interface ITelephone
{
bool offHook
{
get;
}
void PickUpReceiver(); // поднятие трубки void HangUpReceiver(); // опускание трубки void Dial(string n); // набор
}
// POTSPhone implements the ITelephone interface public class POTSPhone : ITelephone
{
//private members holds state about the hook
//status of the receiver and if we're in a
//call or not.
private bool m_offHook; private bool m_activeCall;
//read only property as required by ITelephone
//returns the boolean state of the hook status
//of the receiver.
public bool offHook
{
get { return m_offHook; }
}
//constructor to initialize the POTSPhone public POTSPhone()
{
m_offHook = false; m_activeCall = false;
}
//take the receiver
public void PickUpReceiver()
{
m_offHook = true;
}
//return the phone to on hook and end any
//active calls
public void HangUpReceiver()
{
m_offHook = false; m_activeCall = false;
}
//dial a phone number
//requires that the phone be off hook
//requires that we're not already in an active call public void Dial(string n)
{
if (!this.offHook)
{
Console.WriteLine("Phone must be off-hook before dialing."); return;
}
if (m_activeCall)
{
Console.WriteLine("Already in a call."); return;
}
m_activeCall = true;
Console.WriteLine("Dialing " + n);
}
}
----
using System;
class InterfaceExample
{
static void Main()
{
POTSPhone t = new POTSPhone();
//try dialing before we pick up the receiver t.Dial("555-1212");
//dial according to the interface for a POTS phone t.PickUpReceiver();
t.Dial("555-1212"); t.HangUpReceiver();
}
}
using System;
public class AutoDialer
{
public void Call(string[] numbers, string message, ITelephone phone)
{
foreach (string n in numbers)
{
phone.PickUpReceiver();
phone.Dial(n);
Console.WriteLine("Reading \"" + message + "\" to " + n); phone.HangUpReceiver();
}
}
}
class Telemarketer
{
static void Main()
{
POTSPhone t = new POTSPhone(); CordlessPhone c = new CordlessPhone();
string[] numbers = new string[4];
numbers[0] = "555-1211"; numbers[1] = "555-1212"; numbers[2] = "555-1213"; numbers[3] = "555-1214";
AutoDialer a = new AutoDialer();
a.Call(numbers, "Hello. Am I interrupting dinner?", t); a.Call(numbers, "Hello. Am I interrupting dinner?", c);
}
}
Теперь вопросы к обсуждению.
1. Как Вы можете заметить, здесь отсутствует класс CordlessPhone. Создайте новый класс
CordlessPhone, который реализует интерфейс ITelephone способом совершенно отличным от имплементаци в классе POTSPhone, а затем скомпилируйте программу Telemarketer и проследите как она работает.
Пример:
using System;
using System.Collections.Generic; using System.Text;
namespace Telephone
{
public interface ITelephone
{
bool offHook
{
get;
}
void PickUpReceiver(); // поднятие трубки void HangUpReceiver(); // опускание трубки void Dial(string n); // циферблат
}
// POTSPhone implements the ITelephone interface public class POTSPhone : ITelephone
{
//private members holds state about the hook
//status of the receiver and if we're in a
//call or not.
private bool m_offHook;//Состояние поднятости трубки (поднята, опущена) private bool m_activeCall;//Состояние режима телефона (активный вызов и нет)
//read only property as required by ITelephone
//returns the boolean state of the hook status
//of the receiver.
public bool offHook
{
get { return m_offHook; }
}
//constructor to initialize the POTSPhone public POTSPhone()
{
m_offHook = false; m_activeCall = false;
}
//take the receiver
public void PickUpReceiver()
{
m_offHook = true;
}
//return the phone to on hook and end any
//active calls
public void HangUpReceiver()
{
m_offHook = false; m_activeCall = false;
}
//dial a phone number
//requires that the phone be off hook
//requires that we're not already in an active call public void Dial(string n)
{
if (!this.offHook)
{
Console.WriteLine("Phone must be off-hook before dialing."); return;
}
if (m_activeCall)
{
Console.WriteLine("Already in a call."); return;
}
m_activeCall = true;
Console.WriteLine("Dialing " + n);
}
}
public class CordlessPhone : ITelephone
{
//private members holds state about the hook
//status of the receiver and if we're in a
//call or not.
private bool m_on_off;//Состояние включенности трубки (включена, выключена) private bool m_activeCall;//Состояние режима телефона (активный вызов и нет) private bool m_on_zone;//Факт нахождения трубки в зоне действия станции private bool battary;//Уровень заряда батареи
//read only property as required by ITelephone
//returns the boolean state of the hook status
//of the receiver. public bool offHook
{
get { return m_on_off; }
}
//constructor to initialize the POTSPhone public CordlessPhone()
{
battary = false;//Состояние заряда батареи
m_on_zone = false;//Состояние нахождения в зоне действия станции m_on_off = false;//Состояние трубки (вкл/выкл)
m_activeCall = false;//Состояние активного звонка
}
//take the receiver
public void PickUpReceiver()
{
m_on_off = true;
}
//return the phone to on hook and end any
//active calls
public void HangUpReceiver()
{
m_on_off = false; m_activeCall = false;
}
//Вхождение в зону действия станции public void OnZone()
{
m_on_zone = true;
}
//Процесс заряда батареи public void Charge_Battary()
{
battary = true;
}
//dial a phone number
//requires that the phone be off hook