Wykorzystanie wyrażeń lambda w naszych klasach

Wyrażenia lambda jest to nowa konstrukcja wprowadzona do C# 3.0 pozwalająca w łatwy i przejrzysty sposób na "szybko" zdefiniować jakąś funkcję. W tej notce napiszę jak można je użyć do definiowan

Nadrzędnym typem każdego wyrażenia lambda jest typ Func<T1, T2, T3, T4, TResult> gdzie T1-T4 są typami argumentów, a TResult typem wyniku. Nie jesteśmy oczywiście przywiązani do czterech parametrów wejściowych, gdyż zostały zdefiniowane typy od 0 do 4 argumentowe (zmienia się liczba wystąpień TX). TResult jest natomiast parametrem obowiązkowym.

W poniższym przykładzie zdefiniuję metodę w klasie Matrix, która jako argument będzie otrzymywała wyrażenie lambda (funkcję) i wykona ją dla każdego z elementów macierzy. Przechodząc do praktyki będzie to wyglądało tak:

  1. public void DoForAllElements(Func< T , T> function)
  2. {
  3.  
  4. for (int i = 0; i < N; i++)
  5. {
  6. for (int j = 0; j < M; j++)
  7. {
  8. this[i, j] = function(this[i, j]);
  9. }
  10. }
  11. }
  12.  

Wykorzystać ją możemy w sposób następujący:

  1. var A = new Matrix< Double , DoubleCalculator>();
  2. A.DoForAllElements( x => Math.Sqrt(x) );
  3.  

Prawda, że proste? :)

Wpis dokonany przez Przemysław Walkowiak dnia 24 February 2008.
Tagi: , | Brak komentarzy

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:

  1. public class Matrix< T >
  2. {
  3. T[,] matrix;
  4. public int N { get; private set; }
  5. public int M { get; private set; }
  6. public Matrix(int n, int m)
  7. {
  8. }
  9.  
  10. public T this[int i, int j]
  11. {
  12. }
  13. public static Matrix< T > operator +(Matrix< T > A, Matrix< T > B)
  14. {
  15. }
  16. public static Matrix< T > operator -(Matrix< T > A, Matrix< T > B)
  17. {
  18. }
  19. public static Matrix< T > operator *(Matrix< T > A, Matrix< T > B)
  20. {
  21. }
  22. }
  23.  

 

Dokonałem następnie implementacji pierwszego z operatorów:

  1. public static Matrix< T > operator +(Matrix< T > A, Matrix< T > B)
  2. {
  3. if (A.N == B.N && A.M == B.M)
  4. {
  5. Matrix< T > result = new Matrix< T >(A.N, A.M);
  6. for (int i = 0; i < A.N; i++)
  7. {
  8. for (int j = 0; j < A.M; j++)
  9. {
  10. result[i, j] = A[i, j] + B[i, j];
  11. }
  12. }
  13. return result;
  14. }
  15. else
  16. {
  17. throw new Exception("Matrices have different dimensions");
  18. }
  19. }

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

Wpis dokonany przez Przemysław Walkowiak dnia 23 February 2008.
Tagi: , , | 1 komentarz

Microsoft SQL Server 2008 CTP6 (February 2008)

Dwa dni temu na stronach Microsoftu można było zauważyć długo oczekiwane następne wydanie CTP SQL Servera 2008, które w przeciwieństwie do CTP5 zaczęło oficjalnie wspierać LINQ to SQL w Visual Studio 2008. Pierwszy kontakt z CTP6 wyszedł dosyć dobrze, bez problemów dało zainstalować się na kilku serwerach (opartych na Windows Server 2008) – nie pojawił się żaden błąd i wszystko działało od ręki. Problemy zaczęły się dopiero w momencie, gdy zapragnąłem zainstalować go na moim laptopie. A zaczęło się to mniej więcej tak ;)

Odinstalowałem (tzn. spróbowałem odinstalować) wpierw poprzednią wersję SQL Server 2008 oraz SQL Server Express 2005, niestety ten proces nie do końca się powiódł, gdyż wystąpił błąd o niezbyt rozbudowanej treści "Setup has encountered the following error: Failed to retrieve data for this request..". W Internecie jedyne co udało mi się znaleźć to opis, że trzeba ręcznie usunąć aplikacje (np. za pomocą Windows Install Clean Up, a następnie wyczyścić pliki z katalogu Program Files). Tak więc też uczyniłem.

Po restarcie systemu i odpaleniu instalatora SQL Server 2008 w niecałe 30s pojawił się znowu identyczny błąd (gdy odpaliłem ręcznie instalator SQL Database Engine wyświetlił jakieś dziwne zapytanie SQL i również instalacja się nie powiodła). Google już niestety na ten temat milczało. Ale ponieważ tak łatwo nie można się poddać, więc szukałem dalej;).

Rozwiązanie problemu znajdowało się w sercu systemu Windows – w rejestrze :) Postanowiłem być trochę brutalny i usunąłem wszystkie wpisy związane z SQL Serverem z klucza HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ (delikatne próby usuwania wybiórczych wpisów także spełzły na niczym). Efektem tego było szczęśliwe zainstalowanie Microsoft SQL Server 2008 CTP6. Można więc wracać już do zabawy :)

Download: Microsoft SQL Server 2008 CTP6 (February 2008)

Wpis dokonany przez Przemysław Walkowiak dnia 22 February 2008.
Tagi: , , | Brak komentarzy

LINQ to XSD

Dzisiaj wyszła kolejna wersja Alpha 0.2 LINQ to XSD. Tym razem już działająca z Visual Studio 2008. Niestety chwilowo nie mam czasu, aby dokończyć moją kostkę, ale wiem już przynajmniej jakiego rozwiązania wybiorę :)

Download: LINQ to XSD Alpha 0.2

Wpis dokonany przez Przemysław Walkowiak dnia 21 February 2008.
Tagi: , , , | Brak komentarzy