Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Індексатори




Метод Main

 

Метод, якому передається управління після запуску програми, повинен мати ім'я Main і бути статичним. Він може приймати параметри із зовнішнього оточення і повертати значення в середовище, що викликало. Передбачається два варіанти методу - з параметрами і без параметрів:

 

// без параметрів:

static тип Main() {... }

static void Main() {... }

// з параметрами:

static тип Main (string[] args){/*...*/}

static void Main(string[] args){/*...*/}

 

Параметри, що розділяються пропусками, задаються при запуску програми з командного рядка після імені виконуваного файлу програми. Вони передаються в масив args.

Якщо метод повертає значення, воно має бути цілого типу, якщо не повертає, він повинен описуватися як void. В цьому випадку оператор повернення з Main можна не вказувати, а середовище, що викликало, автоматично набуде нульового значення, що означає успішне завершення. Ненульове значення зазвичай означає аварійне завершення, наприклад:

 

static int Main(string[] args)

{

if (... /* все пропало */) return 1;

 

if (.../* абсолютно все пропало */) return 100;

}

 

Повертаєме значення аналізується в командному файлі, з якого запускається програма. Зазвичай це робиться для того, щоб можна було прийняти рішення, чи виконувати командний файл далі. У лістингу 7.2 наводиться приклад методу Main, який виводить свої аргументи і чекає натиснення будь-якої клавіші.

 

Лістинг 7.2. Параметри методу Main

using System;

 

namespace ConsoleApplication1

{

class Program

{

static void Main(string[] args)

{

foreach (string arg in args) Console.WriteLine(arg);

Console.Read();

}

}

}

 

Нехай виконуваний файл програми має ім'я Consoleapplication1.exe і викликається з командного рядка:

d:\cs\consoleapplicationl\bin\debug\consoleapplicationl.exe one two three

Тоді на екран буде виведено:

one

two

three

 

Для запуску програми з командного рядка можна скористатися командою Выполнить меню Пуск

 

 

Індексатором є різновид властивості. Якщо у класу є приховане поле, що є масивом, то за допомогою індексатора можна звернутися до елементу цього масиву, використовуючи ім'я об'єкту і номер елементу масиву в квадратних дужках. Іншими словами, індексатор - це індекс для об'єктів.

Синтаксис індексатора аналогічний синтаксису властивості:

 

атрибути специфікатори тип this [ список_параметрів]

{

get код_доступа

set код_доступа

}

 

В даному випадку квадратні дужки є елементом синтаксису, а не вказівкою на необов'язковість конструкції.

Атрибути ми розглянемо пізніше, в розділі 12, а специфікатори аналогічні специфікаторам властивостей і методів. Індексатори найчастіше оголошуються із специфікатором public, оскільки вони входять в інтерфейс об'єкту. Атрибути і специфікатори можуть бути відсутніми.

Код доступу є блоком операторів, які виконуються при отриманні (get) або установці значення (set) елементу масиву. Може бути відсутньою або частина get, або set, але не обидві одночасно. Якщо відсутня частина set, індексатор доступний тільки для читання (read-only), якщо відсутня частина get, індексатор доступний тільки для запису (write-only).

Список параметрів містить одне або декілька описів індексів, по яких виконується доступ до елементу. Найчастіше використовується один індекс цілого типу. Індексатори в основному застосовуються для створення спеціалізованих масивів, на роботу з якими накладаються які-небудь обмеження. У лістингу 7.3 створений клас-масив, елементи якого повинні знаходитися в діапазоні [0, 100]. Крім того, при доступі до елементу перевіряється, чи не вийшов індекс за допустимі межі.

 

Лістинг 7.3. Використання індексаторів

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace examp42

{

class SafeArray

{

public SafeArray(int size)

{

a=new int[size];

length=size;

}

public int Length // властивість розмірність

{

get{return length;}

}

public int this[int i] //індексатор

{

get

{

if(i>=0&&i<length) return a[i];

else

{

error=true;

return 0;

}

}

set

{

if (i >= 0 && i < length

&& value >= 0 && value <= 100) a[i] = value;

else error=true;

}

}

 

public bool error=false; //прихована ознака помилки

int []a; //закритий масив

int length; //закрита розмірність

}

 

class Class1

{

static void Main()

{

int n=60;

SafeArray sa=new SafeArray(n);

for(int i=0;i<n;++i)

{

sa[i]=i*2; // 1 використання індексатора

Console.Write(" "+ sa[i]); // 2 використання індексатора

}

if(sa.error)Console.Write("Error");

}

}

}

 

З лістингу видно, що індексатори описуються аналогічно властивостям. Завдяки застосуванню індексаторів з об'єктом, що містить в собі масив, можна працювати так само, як зі звичайним масивом. Якщо звернення до об'єкту зустрічається в лівій частині оператора привласнення (оператор 1), автоматично викликається метод get. Якщо звернення виконується у складі виразу (оператор 2), викликається метод set.

У класі Safearray прийнята наступна стратегія обробки помилок. Якщо при спробі запису елементу масиву його індекс або значення задані невірно, значення елементу не привласнюється. Якщо при спробі читання елементу індекс не входить в допустимий діапазон, повертається 0. У обох випадках формується значення відкритого поля error, рівне true.

Взагалі кажучи, індексатор не обов'язково має бути пов'язаний з яким-небудь внутрішнім полем даних. У лістингу 7.4 приведений приклад класу Pow2, єдине призначення якого - формувати ступінь числа 2.

 

Лістинг 7.4. Індексатор без масиву

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace examp43

{

 

class Pow2

{

 

public ulong this[int i]

{

get

{

if (i >= 0)

{

ulong res = 1;

for (int k = 0; k < i; k++)// Цикл отримання ступеня

unchecked { res *= 2; }// 1

return res;

}

else return 0;

}// get

}//this

 

}//Pow2

 

class Class1

{

static void Main()

{

try

{

 

int n = 30;

Pow2 pow2 = new Pow2();

for (int i = 0; i < n; ++i)

Console.WriteLine("{0}\t{1}", i, pow2[i]);

}

 

 

catch (Exception e)

{

Console.WriteLine(e.Message);

return;

}

}

}//Class1

}// namespace

 

Оператор 1 виконується в контексті, що не перевіряє, для того, щоб виключення, пов'язане з переповнюванням, не генерувалося. В принципі, дана програма працює і без цього, але якщо помістити клас Pow2 в контекст, що перевіряється, при значенні, що перевищує допустимий діапазон для типу ulong, виникне виключення.

 

Результат роботи програми:

 

Мова С# допускає використання багатовимірних індексаторів. Вони застосовуються для контролю за занесенням даних в багатовимірні масиви. Крім того, вони використовуються при вибірці даних з багатовимірних масивів, оформлених у вигляді класів. Наприклад:

 

int[,] а;

 

Якщо усередині класу оголошений такий двовимірний масив, то заголовок індексатора повинен мати вигляд

 

public int this[int i, int j]

 

 

7.6. Операції класу

 

С# дозволяє перевизначити дію більшості операцій так, щоб при використанні з об'єктами конкретного класу вони виконували задані функції. Приклад:

 

MyObject а, b, с;

c = а + b; // використовується операція складання для класу MyObject

 

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

Операції класу описуються за допомогою методів спеціального вигляду (функцій-операцій). Перевантаження операцій схоже на перевантаження звичайних методів. Синтаксис операції:

 

[атрибути ] специфікатори об’явник_операції тіло

 

Атрибути розглядаються у розділі 12, як специфікатори одночасно використовуються ключові слова public і static. Крім того, операцію можна оголосити як зовнішню (extern).

Об'явник операції містить ключове слово operator, по якому і впізнається опис операції в класі. Тіло операції визначає дії, які виконуються при використанні операції у виразі. Тілом є блок, аналогічний тілу інших методів.

При описі операцій необхідно дотримуватись наступних правил:

– операція має бути описана як відкритий статичний метод класу (специфікатори public static);

– параметри в операцію повинні передаватися за значенням (тобто без ключових слів ref або out);

– сигнатури всіх операцій класу повинні розрізнятися.

У С# існують три види операцій класу: унарні, бінарн і і операції перетворення типу.

7.6.1. Унарні операції

 

Можна визначати в класі наступні унарні операції:

+ -! - ++ -- true false

 

Синтаксис об'явника унарної операції:

 

тип operator унарна_операція (параметр)

 

Приклади заголовків унарних операцій:

public static int operator +(MyObject m)

public static MyObject operator -- (MyObject m)

public static bool operator true(MyObject m)

 

Параметр, переданий в операцію, повинен мати тип класу, для якого вона визначається. Операція повинна повертати:

§ для операцій +, -! ~ величину будь-якого типу;

§ для операцій ++ -- величину типу класу, для якого вона відзначається;

§ для операцій true і false величину типу bool.

Операції не повинні змінювати значення переданого ним операнда. Операція, що повертає величину типу класу, для якого вона визначається, повинна створити новий об'єкт цього класу, виконати з ним необхідні дії і передати його як результат.

Префіксний і постфіксний інкременти не розрізняються.

Як приклад удосконалимо приведений в лістингу 7.3 клас Safearray для зручної і безпечної роботи з масивом. До класу внесені наступні зміни:

§ доданий конструктор, що дозволяє ініціалізувати масив звичайним масивом або серією цілочисельних значень довільного розміру;

§ додана операція інкремента;

§ доданий допоміжний метод Print виведення масиву;

§ змінена стратегія обробки помилок виходу за межі масиву;

§ знята вимога, щоб елементи масиву приймали значення в заданому діапазоні.

Текст програми приведений в лістингу 7.5.

 

Лістинг 7.5. Визначення операції інкремента для класу

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace examp44

{

class SafeArray

{

public SafeArray(int size) // конструктор

{

a = new int[size];

length = size;

}

public SafeArray(params int[] arr) //новий конструктор

{

length = arr.Length;

a = new int[length];

for (int i = 0; i < length; ++i) a[i] = arr[i];

}

 

 

public static SafeArray operator ++(SafeArray x) // ++

{

SafeArray temp = new SafeArray(x.length);

for (int i = 0; i < x.length; ++i)

temp[i] = ++x.a[i];

return temp;

}

 

 

public int this[int i] // індексатор

{

get

{

if (i >= 0 && i < length) return a[i];

else throw new IndexOutOfRangeException(); // виключення

}

set

{

if (i >= 0 && i < length) a[i] = value;

else throw new IndexOutOfRangeException(); // виключення

}

}

public void Print(string name) // виведення на екран

{

Console.WriteLine(name + ": ");

for (int i = 0; i < length; ++i)

Console.Write("\t" + a[i]);

Console.WriteLine();

}

int[] a; // закритий масив

int length; // закрита розмірність

}

 

class Class1

{

static void Main()

{

try

{

int[] f = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

SafeArray a1 = new SafeArray(f);

a1.Print("Масив 1");

a1++;

a1.Print("Інкремент масиву 1");

}

catch (Exception e) // обробка виключення

{

Console.WriteLine(e.Message);

}

}

}

}

7.6.2. Бінарні операції

 

Можна визначати в класі наступні бінарні операції:

 

+ - * / % & | ^ << >> ==!= > < >= <=

 

Синтаксис об'явника бінарної операції:

 

тип operator бінарна_операція (параметр1, параметр2)

 

Приклади заголовків бінарних операцій:

 

Cjblic static MyObject operator + (MyObject m1, MyObject m2)

Cublic static bool operator = = (MyObject m1, MyObject m2)

 

Хоч би один параметр, переданий в операцію, повинен мати тип класу, для якого вона визначається. Операція може повертати величину будь-якого типу.

Операції == і! =, > і <, >= і <= визначаються тільки парами і зазвичай повертають логічне значення. Найчастіше в класі визначають операції порівняння на рівність і нерівність для того, щоб забезпечити порівняння об'єктів, а не їх посилань, як визначено за умовчанням для посилальних типів. Перевантаження операцій відношення вимагає знання інтерфейсів, тому вона розглядається пізніше.

Приклад визначення операції складання для класу Safearray, описаного в попередньому розділі, приведений в лістингу 7.6. Залежно від операндів операція або виконує поелементне складання двох масивів, або додає значення операнда до кожного елементу масиву.

 

Лістинг 7.6. Визначення операції складання для класу SafeArray

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace examp47

{

class SafeArray

{

public SafeArray(int size)

{

a = new int[size];

length = size;

}

 

public SafeArray(params int[ ] arr)

{

length = arr.Length;

a = new int[length];

for (int i = 0; i < length; ++i) a[i] = arr[i];

}

 

public static SafeArray operator + (SafeArray x, SafeArray y) // +

{

int len = x.length < y.length? x.length: y.length;

SafeArray temp = new SafeArray (len);

for (int i = 0; i < len; ++i) temp[i] = x[i] + y[i];

return temp;

}

 

public static SafeArray operator + (SafeArray x, int y) // +

{

SafeArray temp = new SafeArray(x.length);

for (int i = 0; i < x.length; ++i) temp[i] = x[i] + y;

return temp;

}

public static SafeArray operator +(int x, SafeArray y) // +

{

SafeArray temp = new SafeArray(y.length);

for (int i = 0; i < y.length; ++i) temp[i] = x + y[i];

return temp;

}

public static SafeArray operator ++ (SafeArray x) // ++

{

SafeArray temp = new SafeArray(x.length);

for (int i = 0; i < x.length; ++i) temp[i] = ++x.a[i];

return temp;

}

public int this[int i] // []

{

get

{

if (i >= 0 && i < length) return a[i];

else throw new IndexOutOfRangeException();

}

set

{

if (i >= 0 && i < length) a[i] = value;

else throw new IndexOutOfRangeException();

}

}

public void Print(string name)

{

Console.WriteLine(name + ": ");

for (int i = 0; i < length; ++i) Console.Write("\t" + a[i]);

Console.WriteLine();

}

int[] a; //закритий масив

int length; //закрита розмірність

}

 

class Classl

{

static void Main()

{

try

{

SafeArray a1 = new SafeArray(5, 2, -1, 1, -2);

a1.Print ("Масив 1");

SafeArray a2 = new SafeArray(1, 0, 3);

a2.Print("Масив 2");

SafeArray a3 = a1 + a2;

a3.Print("Сума масивів 1 и 2");

a1 = a1 + 100; // 1

a1.Print ("Масив 1 + 100");

a1 = 100 + a1; // 2

a1.Print ("100 + масив 1");

a2 += ++a2+1; // 3

a2.Print("++a2.a2 + a2 + 1");

}

catch (Exception e)

{

Console.WriteLine(e.Message);

}

}

}

}

 

Щоб забезпечити можливість складання з константою, операція складання перевантажена двічі для випадків, коли константа є першим і другим операндом (оператори 2 і 1).

Складну операцію привласнення += (оператор 3) визначати не потрібно, та це і неможливо. При її виконанні автоматично викликається спочатку операція складання, потім привласнення.

 

7.6.3. Операції перетворення типу

 

Операції перетворення типу забезпечують можливість явного і неявного перетворення між призначеними для користувача типами даних. Синтаксис об’явника операції перетворення типу:

 

implicit operator тип (параметр) // неявне перетворення

explicit operator тип (параметр) // явне перетворення

 

Ці операції виконують перетворення з типу параметра в тип, вказаний в заголовку операції. Одним з цих типів має бути клас, для якого визначається операція. Таким чином, операції виконують перетворення або типу класу до іншого типу, або навпаки. Перетворювані типи не мають бути зв'язані стосунками спадкоємства. Приклади операцій перетворення типу для класу Monster:

 

public static implicit operator int(Monster m)

{

return m.health;

}

 

public static explicit operator Monster(int h)

{

return new Monster(h, 100, "FromInt");

}

 

Нижче приведені приклади використання цих перетворень в програмі. Не треба шукати в них сенс, вони просто ілюструють синтаксис:

 

Monster Masha = new Monster(200, 200, "Masha");

int i = Masha; //неявне перетворення

Masha = (Monster) 500; // явне перетворення

 

Неявне перетворення виконується автоматично:

§ при привласненні об'єкту змінній цільового типу, як в прикладі;

§ при використанні об'єкту у виразі, що містить змінні цільового типу;

§ при передачі об'єкту в метод на місце параметра цільового типу;

§ при явному приведенні типу.

Явне перетворення виконується при використанні операції приведення типу. Всі операції класу повинні мати різні сигнатури. Ключові слова implicit і explicit в сигнатуру не включаються, отже, для одного і того ж перетворення не можна визначити одночасно явну і неявну версії.

Неявне перетворення слід визначати так, щоб при його виконанні не виникала втрата точності і не генерувалися виключення. Якщо ці ситуації можливі, перетворення слід описати як явне.

 

 




Поделиться с друзьями:


Дата добавления: 2014-12-27; Просмотров: 1513; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.012 сек.