Арифметические операции для классов с обобщенным типом - C#

Узнай цену своей работы

Формулировка задачи:

Доброго времени! Никак не могу разобраться в проблеме и прошу помощи и совета у авторитетных гуру! Суть в следующем. Есть класс Matrix - поддерживает операции с матрицами и т.д. Класс объявлен как:
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];
, дескать, невозможно совершить операцию + между типами Т и Т. Отсюда вопрос: 1. Почему в данном случае не работает ограничение
where T: struct
2. Какой есть выход из ситуации - третий день бьюсь, но похоже отсутствие достаточного количества мозгов не позволяет ничего придумать Задача дополняется наличием структуры типа Fraction (дробь), в которой также переопределены арифметические операторы. При этом T должен поддерживать тип Fraction Код дроби:
        #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; } }

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

9   голосов , оценка 4.333 из 5
Похожие ответы