Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Недолік обмеження операцій

Читайте также:
  1. А) Характеристика методів візуалізації сечової системи, показання до застосування, їх можливості та обмеження.
  2. Б) Характеристика методів візуалізації статевої системи, показання до застосування, їх можливості та обмеження.
  3. БЕЗПОСЕРЕДНІЙ ПІСЛЯОПЕРАЦІЙНИЙ ДОГЛЯД
  4. Для обліку операцій за видатками розпорядників коштів призначені
  5. Енергетичне господарство, як елемент операційної системи, його склад, структура управління та основні задачі.
  6. Знайомство з операційною системою (ОС) Windows. Робота з об'єктами в ОС.
  7. Інструменти операційного контролю.

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

// Недопустиме узагальнення! public class BasicOperations<T> where T: operator +, operator -, operator *, operator / { public T Add(T argl, T arg2) { return argl + arg2; } public T Sub(T argl, T arg2) { return argl - arg2; } public T Mul(T argl, T arg2) { return argl * arg2; } public T Div(T argl, T arg2) { return argl / arg2; } }

Необхідність такого роду обмежень (коли в узагальненні виникає потреба у використанні операцій додавання, множення, віднімання, ділення, тощо для об’єктів-змінних параметру типу) на практиці виникає досить часто. Наприклад, така необхідність буде виникати при реалізації багатьох методів узагальнення Matrix<T> − узагальненого класу для роботи з матрицями, елементи яких мають тип T. Зокрема, операцій додавання, множення та визначення протилежного над об’єктами-змінними типу T буде вимагати метод обчислення визначника квадратної матриці з елементами загального типу T.

Та все ж таки бажаного результату у цьому випадку можна досягти. Наприклад, для цього ми можемо використати інтерфейс, який підтримує зазначені операції, і потім вказати обмеження на цей інтерфейс. Реалізуємо цей підхід на прикладі розробки узагальнення Matrix<T> для роботи з матрицями.

Нагадаємо, що матриця − математичний об’єкт, записаний у вигляді прямокутної таблиці елементів кільця або поля (наприклад раціональних, p-адичних, дійсних або комплексних чисел). В свою чергу поле − це всяка множина з двома бінарними операціями (адитивною та мультиплікативною), якщо вона разом з цими операціями утворює комутативне асоціативне кільце з одиницею та всі ненульові елементи якої мають обернений. Програмно таку абстракцію можна подати у вигляді наступного узагальненого інтерфейсу:

interface IField<F> { // адитивна операція (додавання) поля F F Add(F a, F b); // мультиплікативна операція (множення) поля F F Mul(F a, F b); // властивість, яка всякому елементу поля F повертає його протилежний F Adverse { get; } // властивість, яка всякому елементу поля F повертає його обернений F Inverse { get; } // властивість, яка повертає нуль поля F F Zero { get; } // властивість, яка повертає одиницю поля F F One { get; } }

Тепер, як було зазначено вище, визначимо узагальнений клас Matrix<T>, наклавши на параметр типу T обмеження на реалізацію узагальненого інтерфейсу IField<T>:

class Matrix<T> where T: IField<T> { // прямокутний масив елементів матриці T[,] array; }

Використання операцій над екземплярами параметру типу T проілюструємо на прикладі реалізації методу Determinant для обчислення визначника матриці.

Нагадаємо, що мінором елемента (ij-мінором) матриці , називається матриця розмірності , яка отримується із матриці видаленням i-го рядка та
j-го стовпця. Визначник або детермінант матриці розмірності можна обчислити рекурсивно за допомогою мінорів наступним чином:

Таким чином отримуємо:

class Matrix<T> where T: struct, IField<T> { // прямокутний масив елементів матриці T[,] array; // конструктори з параметрами public Matrix(int rowCount, int colCount) { array = new T[rowCount, colCount]; } public Matrix(T[,] arg) { array = arg; } // властивість повернення кількості рядків матриці public int RowCount { get { return array.GetLength(0); } } // властивість повернення кількості стовпців матриці public int ColCount { get { return array.GetLength(1); } } // індексатор для зручності доступу до елементів матриці public T this[int i, int j] { get { return array[i,j]; } } // метод визначення ij-мінору матриці public Matrix<T> IJMinor(int I, int J) { Matrix<T> tmp = new Matrix<T>(RowCount-1, ColCount-1); for (int i = 0; i < RowCount; i++) for (int j = 0; j < ColCount; j++) { if (i < I && j < J) tmp.array[i, j] = array[i, j]; if(i < I && j > J) tmp.array[i, j - 1] = array[i, j]; if (i > I && j < J) tmp.array[i - 1, j] = array[i, j]; if (i > I && j > J) tmp.array[i - 1, j - 1] = array[i, j]; } return tmp; } // властивість, що повертає значення детермінанту квадратної матриці public T Determinant { get { if (RowCount == ColCount) { if (RowCount == 1) return array[0, 0]; else { // присвоєння змінній-об’єкту типу T значення за замовчуванням[11] T det = default(T); for (int j = 0; j < RowCount; j++) if (j % 2 == 0) det = det.Add(det, det.Mul(array[0, j], IJMinor(0, j).Determinant)); else det = det.Add(det, det.Mul(array[0, j], IJMinor(0, j).Determinant).Adverse); return det; } } else throw new Exception("Детермiнант не є числовою характеристикою прямокутної матрицi!"); } } // метод виводу матриці на екран public void Display() { for (int i = 0; i < RowCount; i++) { for (int j = 0; j < ColCount; j++) Console.Write("{0} ", array[i,j]); Console.WriteLine(); } } }

Із визначення класу Matrix<T> випливає, що в якості аргументу типу T можуть виступати тільки ті класи, які реалізують узагальнений інтерфейс IField<T>. Реалізацію IField<T> проілюструємо на прикладі визначення класу для поля дійсних чисел у вигляді наступної структури:

struct Real: IField<Real> { // значення елемента поля дійсних чисел double value; // нуль поля дійсних чисел static double zero = 0; // одиниця поля дійсних чисел static double one = 1; // реалізація узагальненого інтерфейсу IFieldStructure для поля дійсних чисел public Real Add(Real a, Real b) { return a.value + b.value; } public Real Mul(Real a, Real b) { return a.value * b.value; } public Real Adverse { get { return -value; } } public Real Inverse { get { return 1 / value; } } public Real Zero { get { return Real.zero; } } public Real One { get { return Real.one; } } // перевантаження неявного приведення типу double до Real public static implicit operator Real(double v) { Real tmp = new Real(); tmp.value = v; return tmp; } // перевантаження неявного приведення типу Real до double public static implicit operator double(Real v) { return v.value; } // перевантаження методу базового класу public override string ToString() { return value.ToString(); } }

Тепер розроблене нами узагальнення Matrix<T> може бути використане з аргументами типу Real:

Matrix<Real> M = new Matrix<Real>(new Real[,]{{1,2,3},{2,1,3},{3,1,2}}); Console.WriteLine(M.Determinant);

 

 


[1] Фреймворк − програмне забезпечення, що полегшує розробку та об’єднання різних компонентів великого програмного проекту. На відміну від бібліотек, які поєднують набір підпрограм близьких за функціональністю, фреймворк містить у собі велику кількість різних за призначенням бібліотек, а також допоміжні програми, мову сценаріїв та інше програмне забезпечення.

[2] Компіляція − механізм чи процедура перетворення програмного коду, написаного на одній мові програмування у еквівалентний байт-код (псевдокод) чи у машинний код.

Псевдокод − машинно-незалежний код низького рівня, що генерується транслятором і виконується інтерпретатором.

Машинний код − набір команд, що може зрозуміти й обробити центральний процесор комп’ютера без транслятора.

Транслятор − програма або технічний засіб, що виконує перетворення чи іншу обробку текстів програм.

Інтерпретатор − програма чи технічні засоби, необхідні для виконання інших програм. Це різновид транслятора, який здійснює покомандну обробку, перетворення у машинний код та виконання програми (на відміну від компілятора, який транслює у машинні коди всю програму без її виконання). Інтерпретатори можуть працювати як з вихідним кодом програми (англ. source code), написаним мовою програмування, так і з байт-кодом (інтерпретатори байт-коду).

[3] Псевдокод MSIL визначає набір переносних інструкцій, що не залежать від типу (архітектури) процесора. Це платформо незалежний код.

[4] Хоча в більшості випадків методи Main() повертають значення типу void, можливість повертати значення типу int із Main() дозволяє погоджувати C# з іншими мовами, що базуються на C. За домовленістю, повернення значення 0 свідчить про те, що виконання програми пройшло успішно, а будь-якого іншого значення (наприклад, -1) − що в ході виконання програми відбулася помилка (слід мати на увазі, що значення 0 повертається автоматично навіть у випадку, якщо метод Main() повертає void).

[5] У якості альтернативи, замість стандартного циклу for для проходу по вхідному масиву рядків можна також використовувати ключове слово foreach (будемо розглядати пізніше).

[6] Інтегроване середовище розробки − система програмних засобів для розробки програмного забезпечення. Як правило середовище розробки містить у собі текстовий редактор, компілятор і/або інтерпретатор, засоби автоматизації

[7] Програма установки.NET Framework 4.0 SDK (dotnetfx40_full_setup. exe) доступна на сторінці завантаження.NET за адресою http://msdn.microsoft.com/netframework.

[8] Загальноприйнятою є домовленість надавати файлу з кодом на С# розширення.cs.

[9] Про інші параметри компілятора C# для роботи із вихідними файлами, а також параметри для роботи зі вхідними файлами, ресурсами, помилками, тощо можна дізнатись увівши в командному рядку команду сsc -? або csc /help.

[10] У мові C # є два різновиди типів даних: типи значень (value based types) та посилальні типи (reference based types). Змінна посилального типу зберігає тільки адреси об’єктів, а змінна типу значення − сам об’єкт. До типів значень належать структури (структурами у мові C# є і всі прості типи даних) та переліки. Всі інші типи у мові C# є посилальними, зокрема тип string.

[11] Ключове слово default в узагальненнях використовується для встановлення значень за замовчуванням для параметра типу. Замовчування для параметрів типу наступні:

· значення за замовчуванням числових величин дорівнює нулю;

· посилальні типи мають значення за замовчуванням null;

· поля структур встановлюються у 0 (для типів-значень) або в null (для посилальних типів).


Дата добавления: 2015-10-26; просмотров: 124 | Нарушение авторских прав


Читайте в этой же книге: Загальна характеристика платформи .Net Framework | Бібліотека базових типів BCL | Лістинг 2. Текст програми на мові C#, яка виводить на консоль привітання тільки тим користувачам, імена яких передаються як параметри командного рядка | Синтаксис опису класу | Властивості та індексатори | Агрегація та композиція | Організація роботи із файлами даних стандарту XML | Делегати в якості параметрів | Події: створення та обробка |
<== предыдущая страница | следующая страница ==>
Абстрактні класи| Деякі класи неузагальнених колекцій

mybiblioteka.su - 2015-2024 год. (0.008 сек.)