[OOP] Defining Classes Part Two - Задача 8,9,10


8

 

Колеги отварям тема свързана с класа Маtrix 
 
7. Define a class Matrix<T> to hold a matrix of numbers (e.g. integers, floats, decimals).
 
8. Implement an indexer this[row, col] to access the inner matrix cells.
 
9. Implement the operators + and - (addition and subtraction of matrices of the same size) and * for matrix multiplication. Throw an exception when the operation cannot be performed. Implement the true operator (check for non-zero elements).
 
Моят въпрос е свързан с 9 задача. Как мога да извадя два елемента от тип T ?
Прочетох в интернет, че T не поддържа операторите +, -, /, *. Eдинственото което ми хрумна е да ги кастна към (dynamic), но не мисля че това е правилния подход. 

в C# OOP от Божидар Пенчев (0 точки)


Отговори



0
Предполагам че в случая трябва да вадим матрица от матрица, които съдържат числа, трябва да сложим интерфейс който ограничава да са само числа и да имплементираме операторите.



0
Ами аз не намерих подобен интерфейс. А отностно операторите проблема е че за да намерим новата матрица трябва да направим метод който ги събира( например ). И точно там е проблема не може да се събират,изваждат умножават или събират променливи от тип Т. Този проблем засега го оправих като ги кастнах към динамик( dynamic)

от Божидар Пенчев (0 точки)


5

Аз лично го каствам към dynamic и върши работа, но на следващата лекция задължително ще питам дали е правилен подход.

9. Задача 
ето малко полезни матери по темата:

кой оператори са overloadable: link , link

примери за overload на операторите: link , най-доло има и за true, false

Edit: Ето и сорса на class Matrix. 


от ivivanov (903 точки)


0
Еми явно за сега този dynamic ще ни спасява. Но все си мисля, че има и друг начин, но както казваш следващата лекция ще ни реши проблема. :)

от Божидар Пенчев (0 точки)

0
Този dynamic са го сложили да е по-лесно, така че с подходящите ограничения, не мисля, че трябва да изпитваме угризения, когато го ползваме. @i.ivanov: Вместо "FillMatrix" по-добре ползвай конструктор, public Matrix(T[,] value), с който да си попълниш двумерния масив в класа. Т.е. не е добре в класа Matrix да четеш от конзолата. Възможно е класът да не се ползва само от конзолни приложения и масивът с данни да идва примерно от базата данни или от текстов файл. Прочети си данните в двумерен масив в Main-а на конзолното приложение и този масив подай на конструктора - така спазваш принципа за loose coupling - Matrix не зависи от типа на приложението, което го ползва => possible code reuse ;-)

от vic.alexiev (2299 точки)



18

Ако видите с F12 дефинициите на числовите типове, ще забележите, че те всички са структури и имплементират едни и същи интерфейси. Значи ако си направим клас Matrix<T>

where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T> ще ограничим T до числовите типове. За съжаление няма интерфейс INumber, който да ни позволява да ползваме операторите +, -, *, / за Т, така че в класа Matrix (сигурно?) може да ползваме dynamic. T.e. след като сме ограничили T по този начин, ползването на dynamic вътре вече не е толкова опасно. Ако не ограничим T, потребителят ще може да си прави матрица от StreamReader-и например, за които числовите операции нямат смисъл (и не са дефинирани), така че той си носи отговорност за Exception-ите, които класът ще хвърля. Ако пък сложим ограниченията, ние подсказваме, че тази матрица има смисъл само за числови типове, така че ако някой иска да си прави матрица от StreamReader-и, по-добре да ползва StreamReader[,].

EDIT: Ето и моята матрица: https://github.com/vic-alexiev/TelerikAcademy/tree/master/OOP/Homework%20Assignments/2.%20Defining%20Classes%20Part%20II/08.%20SampleMatrixImplementation


от vic.alexiev (2299 точки)


0
Значи така можела да се ограничи само до числови типове. Не се бях сетил за този номер.Благодаря за разяснението.

от Божидар Пенчев (0 точки)

0
DateTime отговаря на същите условия (where T : struct, IComparable, IFormattable, IConvertible, IComparable




1

"...Моят въпрос е свързан с 9 задача. Как мога да извадя два елемента от тип T ?..Прочетох в интернет, че T не поддържа операторите +, -, /, *. Eдинственото което ми хрумна е да ги кастна към (dynamic), но не мисля че това е правилния подход... "

Трябва да предефинираш операторите +, - и т.н. да могат да работят с твоите типове.
Тук има нагледен пример за + 

http://msdn.microsoft.com/en-us/library/aa288467%28v=vs.71%29.aspx


от ipenev (1013 точки)


0
редакторът е изял двете точки след http и не отваря нищо

от arabella (2576 точки)

0
Оправих, сега работи.

от ipenev (1013 точки)


5

Съгласен съм с колегата vic.alexiev, че интерфейсите, които е предложил, до някаква една голяма степен отговарят на условието, но дори и само where T : Struct, ще свърши същата работа (поне в тези 3 задачи). Също така е добра практика да си създаваме ние изключения (както се вижда е нужно, дори по условие) .

Предоставям и моето решение на задачите : 

https://github.com/Bvaptsarov/Homework/tree/master/10.OOPSecondPart/GenericMatrix


от Prophian (1234 точки)


0
Да и аз избрах варианта с where T: struct. Според msdn това ще ограничи аргументите да са value type http://msdn.microsoft.com/en-us/library/d5x73970%28v=vs.80%29.aspx . А нужно ли е добавянето и на другите интерфейси както ти си направил или и само struct е ОК.


0
Друг интерфейс в тази задача не ни трябва, в крайна сметка не сравняваме елементи никъде.

от Prophian (1234 точки)



4
Преди въвеждането на dynamic в езика C# този тип задачи също са се решавали. Един от най-известните методи е с външен generic клас Calculator, чиято задача е да събира, изважда, умножава всякакви(еднакви) типове данни (разбира се ние трябва да си имплементираме тези операции) и използваме този калкулатор в нашата матрица, като ако изплзваме матрица от int-ове в нашич клас инстанцираме Calculator

от ivanbuhov (417 точки)


2

Ето и моето решение.
Нещата са доста подобни както на колегите.
Добавил съм дефиниране на оператора !, за да мога да извиквам if(!Matrix<T>)
Поиграх си малко да си оформя изхода на матрицата да е като матрица в ToString() метода
-----------------
|  4  |  -3 |  4  |
-----------------
|  -1 |  8  |  2  |
-----------------


от AsenVal (3487 точки)


0
В темата "[C#] Multidimensional Arrays - 6" задача бях добавил един коментар за конструктор от типа:
// Constructor public Matrix(T[,] matrix) { this.Row = matrix.GetLength(0); this.Column = matrix.GetLength(1); this.matrixArray = matrix; }
Тогава никой не му обърна внимание (съдейки по поствания сорс), но все още мисля, че е важно да не се инициализира вътрешният масив по този начин.
"Ако реша да го използвам и имам
int[,] matrix1 = new int[,] { {1, 2}, {2, 1} };
Matrix

от vic.alexiev (2299 точки)

0
мерси, за обяснението, съгласен съм с теб. Аз затова съм подавал анонимни масиви в констуктора за да избегна това дублиране, но твоето предложение е по-практично.

от AsenVal (3487 точки)



1

Ето и моя код: GitHub

В самите задачи не открихнещо трудно. Единствено си припомних как се събират, изваждат и умножават матрици :DD

Предефинирането на TRUE ме забави докато не разбрах, че трябва да предефинирам и FALSE. За което благодаря на Ники.

Въпреки че задачите не бяха сложни успях да схвана начина на действие и логиката на нещата. 

Смятам, че по този начин домашните са ни много полезни :))


от werew (576 точки)


3
Има начин и без ползване на dynamic. Използва се кастване към Т и конвертиране към decimal, понеже е достатъчно голям за да събере всеки от типовете. Пример за събиране на два елемента от масив:
newMatrix[rows, cols] = (T)Convert.ChangeType(Convert.ToDecimal(matrix1[rows, cols]) + Convert.ToDecimal(matrix2[rows, cols]), typeof(T));

от petromaxa (577 точки)


0
Направих го по абсолютно същия начин, за съжаление си изгубих доста от времето за да го открия в интернет, трябваше първо тук да погледна ;).

от stoyanov (2483 точки)


0
Само аз ли разбирам условието:
Implement the true operator (check for non-zero elements).
Като нещо от рода на:
if (matrix[row,col] == true) {
DoSomething();
}
Странното е, че нещо не успявам да го имплементирам да работи така ...
Не виждам смисъл в това с true да проверявам дали в дадена матрица има 0 или не.

ПП: Явно съм само аз.

от nikolaikolarov (2177 точки)


0
По-скоро трябва да overload-неш true оператора, като един вид true стойността ти да дава дали матрицата е ненулева/нулева (зависи от имплементацията). Виж ето тук има добър пример как да се направи подобно нещо http://www.blackwasp.co.uk/CSharpTrueFalseOverload.aspx Нулева матрица не значи дали измежду елементите си има 0, а дали всички елементи са 0.

от PBorukova (1129 точки)

0
Е да де, ама тогава нямаше да е уточнено check for non-zero elements. Сега като се замисля, няма смисъл и от това, което аз мисля да имплементирам, тъй като щом имам индексатор мога директно да си проверя if (matrix[row,col] != 0) ... Явно ще го предефинирам за ненулева матрица. Благодаря за линка!

от nikolaikolarov (2177 точки)