Typy generyczne w C# i „drobne” niedociągnięcie

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)
            {
                Matrix< T > result = new Matrix< T >(A.N, A.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
            {
                throw new Exception("Matrices have different dimensions");
            }
        }

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..

2 Responses to “Typy generyczne w C# i „drobne” niedociągnięcie”

  1. 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?

  2. przemkovv’s world » Blog Archive » Typy generyczne w C# i „drobne” niedociągnięcie…

    Dziękujemy za publikację – Trackback z dotnetomaniak.pl…

Leave a Reply