Арифметические операции для классов с обобщенным типом - C#
Формулировка задачи:
Доброго времени!
Никак не могу разобраться в проблеме и прошу помощи и совета у авторитетных гуру!
Суть в следующем. Есть класс Matrix - поддерживает операции с матрицами и т.д. Класс объявлен как:
что позволяет хранить в матрице значения разных типов
Имеется также перегруженный оператор сложения
Но компилятор ругается на строку , дескать, невозможно совершить операцию + между типами Т и Т.
Отсюда вопрос:
1. Почему в данном случае не работает ограничение 2. Какой есть выход из ситуации - третий день бьюсь, но похоже отсутствие достаточного количества мозгов не позволяет ничего придумать
Задача дополняется наличием структуры типа Fraction (дробь), в которой также переопределены арифметические операторы.
При этом T должен поддерживать тип Fraction
Код дроби:
Но сейчас пока главное разобраться как реализовать арифметику для Т и Т
Class Matrix<T> where T: struct
/// <summary> /// Сложение двух матриц /// </summary> /// <param name="M1">Матрица - первое слагаемое</param> /// <param name="M2">Матрица - второе слагаемое</param> /// <returns>Матрица - сумма</returns> public static Matrix<T> operator + (Matrix<T> M1, Matrix<T> M2) { if (ReferenceEquals(M1, null) || ReferenceEquals(M2, null)) throw new InvalidOperationException(String.Format("[ID:{0},{1}] -> Не создан один из операндов операции!", M1.ID, M2.ID)); Matrix<T> ret_val = new Matrix<T>(M1.Width, M1.Height, null); try { if (!M1.CanAdd(M2)) { throw new ArgumentException(String.Format("[ID:{0},{1}] -> Невозможно выполнить указанную операцию!", M1.ID, M2.ID)); } else { for (int r = 0; r < M1.Height; r++) for (int c = 0; c < M1.Width; c++) ret_val[r, c] = M1[r, c] + M2[r, c]; } } catch (ArgumentException aex) { Log.AddString(aex.Message); } catch (Exception ex){ Log.AddString(ex.Message); } // возврат return ret_val; }
ret_val[r, c] = M1[r, c] + M2[r, c];
where T: struct
#region "Fraction" /// <summary> /// Структура представления рациональной дроби /// nominator - числитель дроби /// denominator - знаменатель дроби /// reducable - Флаг немедленного сокращения дроби-результата выполнения арифметических операций /// </summary> public struct Fraction { private int nominator; public int Nominator { get { return nominator; } } private int denominator; public int Denominator { get { return denominator; } } private static bool reducable; public static bool Reducable { get { return reducable; } set { reducable = value; } } /// <summary> /// Конструктор по целому значению /// </summary> /// <param name="Value">Целое число, которое будет числителем дроби (знаменатель=1)</param> public Fraction(int Value) { nominator = Value; denominator = 1; } /// <summary> /// Конструктор по числителю и знаменателю /// </summary> /// <param name="Nom">Устанавливает числитель дроби</param> /// <param name="Denom">Устанавливает знаменатель дроби</param> public Fraction(int Nom, int Denom) { if (Denom == 0) { nominator = 0; denominator = 1; throw new ArgumentException("Знаменатель дроби не может быть нулевым!"); } else { nominator = Nom; denominator = Denom; } } /// <summary> /// Конструктор копирования дроби /// </summary> /// <param name="F">Копирует числитель и знаменатель из указанной дроби F</param> public Fraction(Fraction F) { nominator = F.nominator; denominator = F.denominator; } /// <summary> /// Переопределение стандартного вывода дроби в виде строки /// </summary> /// <returns>Строка в формате n/d</returns> public override string ToString() { return String.Format("{0}/{1}", nominator, denominator); } /// <summary> /// Декомпозиция дроби /// В результате декомпозиции дробь становиться правильной (целая часть отсекается и возвращается как результат /// </summary> /// <returns>Целая часть дроби</returns> public int Decompose() { int ret_val = (nominator - nominator % denominator) / denominator; nominator = nominator % denominator; return ret_val; } /// <summary> /// Сокращение дроби (деление числителя и знаменателя на НОД) /// </summary> public void Reduce() { for (int i = nominator > denominator ? nominator : denominator; i >1; i--) { if (nominator % i == 0 && denominator % i == 0) { nominator /= i; denominator /= i; break; } } } /// <summary> /// Проведение операции сложения двух дробей /// </summary> /// <param name="F1">Первое слагаемое</param> /// <param name="F2">Второе слагаемое</param> /// <returns>Результат сложения двух дробей (результат будет сокращен, если установлено свойство Reducable)</returns> public static Fraction operator +(Fraction F1, Fraction F2) { Fraction ret_val = new Fraction(); if (F1.denominator == F2.denominator) { ret_val.denominator = F1.denominator; ret_val.nominator = F1.nominator + F2.nominator; } else { ret_val.denominator = F1.denominator * F2.denominator; ret_val.nominator = F1.nominator * F2.denominator + F2.nominator * F1.denominator; } // reduce if(reducable) ret_val.Reduce(); // return return ret_val; } /// <summary> /// Проведение операции вычитания двух дробей /// </summary> /// <param name="F1">Уменьшаемое</param> /// <param name="F2">Вычитаемое</param> /// <returns>Результат вычитания двух дробей (результат будет сокращен, если установлено свойство Reducable)</returns> public static Fraction operator -(Fraction F1, Fraction F2) { Fraction ret_val = new Fraction(); if (F1.denominator == F2.denominator) { ret_val.denominator = F1.denominator; ret_val.nominator = F1.nominator - F2.nominator; } else { ret_val.denominator = F1.denominator * F2.denominator; ret_val.nominator = F1.nominator * F2.denominator - F2.nominator * F1.denominator; } // reduce if (reducable) ret_val.Reduce(); // return return ret_val; } /// <summary> /// Проведение операции умножения двух дробей /// </summary> /// <param name="F1">Первый множитель</param> /// <param name="F2">Второй множитель</param> /// <returns>Результат умножения двух дробей (результат будет сокращен, если установлено свойство Reducable)</returns> public static Fraction operator *(Fraction F1, Fraction F2) { Fraction ret_val = new Fraction(); ret_val.denominator = F1.denominator * F2.denominator; ret_val.nominator = F1.nominator * F2.nominator; // reduce if (reducable) ret_val.Reduce(); // return return ret_val; } /// <summary> /// Проведение операции деления двух дробей /// </summary> /// <param name="F1">Делимое/param> /// <param name="F2">Делитель</param> /// <returns>Результат деления двух дробей (результат будет сокращен, если установлено свойство Reducable)</returns> public static Fraction operator /(Fraction F1, Fraction F2) { Fraction ret_val = new Fraction(); ret_val.nominator = F1.nominator * F2.denominator; ret_val.denominator = F1.denominator * F2.nominator; // reduce if (reducable) ret_val.Reduce(); // return return ret_val; } /// <summary> /// Неявное преобразование целого числа в дробь /// </summary> /// <param name="Val">Целое число для преобразования</param> /// <returns>Возвращаемая дробь, числителем которой является Val, а знаменателем - 1</returns> public static implicit operator Fraction(int Val) { Fraction F = new Fraction(Val); return F; } /// <summary> /// Явное преобразование дроби в целое число /// </summary> /// <param name="F">Дробь для преобразования</param> /// <returns>Возвращаемое значение - целая часть дроби</returns> public static explicit operator int(Fraction F) { return F.Decompose(); } /// <summary> /// Явное преобразование дроби в число с плавающей точкой /// </summary> /// <param name="F">Дробь для преобразования</param> /// <returns>Возвращаемое значение - вычисленная дробь в десятичном формате с плавающей точкой</returns> public static explicit operator double(Fraction F) { double ret_val; ret_val = (double)F.nominator / (double)F.denominator; return ret_val; } } #endregion
Решение задачи: «Арифметические операции для классов с обобщенным типом»
textual
Листинг программы
private int nominator; /// <summary> /// Числитель /// </summary> public int Nominator { get { return nominator; } } private int denominator; /// <summary> /// Знаменатель /// </summary> public int Denominator { get { return denominator == 0 ? 1 : denominator; } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д