Zacznę może od tego, że potrzebuję w pewnym projekcie pisanym w C# obsługę macierzy (dodawanie, mnożenie, ślad, itp). Konkretniej chodzi o macierz skonstruowaną z elementów typu prostego Double, ale dobrą cechą byłaby jej uniwersalność (czyli obsługa dowolnych typów) – w skrócie macierz generyczna. Ponieważ jestem troszku leniwy więc rozpocząłem poszukiwania odpowiednich bibliotek w Internecie. Niestety jedynym rozwiązaniem godnym przejrzenia, aczkolwiek niespełniącym moich wymagań była biblioteka CSML. Wadą jej polega na tym, że natywnie operuje na liczbach zespolonych (co można oczywiście zarzutować w przestrzeń liczb rzeczywistch) i nie ma domyślnie zrobionej konwersji Double na Complex.
Zdziwiło mnie, że taka ważna struktura w obliczeniach numerycznych nie dorobiła się pożądnej implementacji (dodam jeszcze: darmowej).. No cóż, w takim razie należy samemu napisać odpowiedni kod.
Zacząłem od stworzenia szkieletu klasy:
public class Matrix< T > { T[,] matrix; public int N { get; private set; } public int M { get; private set; } public Matrix(int n, int m) { } public T this[int i, int j] { } public static Matrix< T > operator +(Matrix< T > A, Matrix< T > B) { } public static Matrix< T > operator -(Matrix< T > A, Matrix< T > B) { } public static Matrix< T > operator *(Matrix< T > A, Matrix< T > B) { } }
Dokonałem następnie implementacji pierwszego z operatorów:
public static Matrix< T > operator +(Matrix< T > A, Matrix< T > B) { if (A.N == B.N && A.M == B.M) { for (int i = 0; i < A.N; i++) { for (int j = 0; j < A.M; j++) { result[i, j] = A[i, j] + B[i, j]; } } return result; } else { } }
Próba kompilacji i... błąd: "Operator '+' cannot be applied to operands of type 'T' and 'T'". W sumie prawda, skąd kompilator ma wiedzieć, czy typ T ma zaimplementowany operator dodawania. Właśnie po to wprowadzono system reguł mogący wymusić na danym typie kilka cech. Zaglądam więc do dokumentacji MSDN i niestety nic ciekawego nie znalazłem. Odpalam wyszukiwarkę dotarłem do kilku wątków o tym samym problemie i jedyną odpowiedzią jest to, że: nie można czegoś takiego zrobić ponieważ Double jest typem prostym.
Ostatecznie jest jeszcze jedno rozwiązanie ("Using generics for calculations"), ale moim zdaniem nie do końca jest ono wzorowe z tego względu, że należałoby stosować dodatkową warstwę pomiędzy typami Int32, Double a naszą klasą generyczną. Ale dużego wyboru nie ma..
A gdybys jawnie przeciążył metodę dodawania dla typu double, tak, żeby kompilator miał świadomość tego, ze operator + istnieje w double i robi dokladnie to co normalnie?
przemkovv’s world » Blog Archive » Typy generyczne w C# i „drobne” niedociągnięcie…
Dziękujemy za publikację – Trackback z dotnetomaniak.pl…