Niespodzianka w przekazywaniu przez referencję

Co powiesz na poniższy kod? Co się stanie?

   1: static void Main(string[] args)
   2: {
   3:     StringBuilder sb = new StringBuilder();
   4:     Method(sb);
   5:     Console.WriteLine(sb.ToString());
   6: }
   7:  
   8: static void Method(StringBuilder fooSB)
   9: {
  10:     fooSB.Append("test");
  11:     fooSB = null;
  12: }

Muszę Ci powiedzieć, że źle zgadałem co się stanie. Pierwszą moją myślą, było, że podczas wykonania się programu w linijce 5 zostanie wyrzucony wyjątek NullReferenceException. A co się okazało po uruchomieniu programu w Visual Studio? Wyświetlił się napis “test”. Co jak już napisałem z początku mnie zaskoczyło.

No ale w czym tkwi szczegół. Przecież obiekty do metod są przekazywane przez referencje i w tym przypadku tak powinno się wykonać. Nawet dowodzi to, że do StringBuildera został dodany napis “test”. Szczegół w tym, że sama referencja jest przekazywana przez wartość. Co oznacza, że do metody jest kopiowany adres, pod którym znajduje się StringBuilder i wszystkie operacje na nim są ok.

Natomiast jeśli zmienimy samą referencje – przypiszemy jej wartość null, to zmienia się wartość kopi oryginalnej referencji, a nie oryginalna referencja i dlatego nie nastąpi wyrzucenie wyjątku w powyższym kodzie.

Natomiast w kodzie poniżej (do sygnatury metody zostało dodane słowo kluczowe ref):

   1: static void Main(string[] args)
   2: {
   3:     StringBuilder sb = new StringBuilder();
   4:     Method(ref sb);
   5:     Console.WriteLine(sb.ToString());
   6: }
   7:  
   8: static void Method(ref StringBuilder fooSB)
   9: {
  10:     fooSB.Append("test");
  11:     fooSB = null;
  12: }

Nastąpi już wyrzucenie wyjątku NullReferenceException, dlatego, że referencja do obiektu jest przekazywana przez referencje, a nie wartość i zmiana referencji w ciele metody, spowoduje zmianę oryginalnej referencji z metody Main.

A Ty wiedziałeś co się stanie?

Tags: ,
Categories: Techniczne

Permalink E-mail | Kick it! | DZone it! | del.icio.us Komentarze (2) Post RSSRSS comment feed

Walidacja w ASP.NET MVC 2

W poprzednim artykule na temat ASP.NET MVC 2 opisałem jak tworzyć widoki. Podczas tworzenia widoku dodania nowego wpisu do księgi gości napotkaliśmy na problem, w którym nie było odpowiedniej walidacji danych i na przykład użytkownik mógł dodać wpis z niepoprawnym formatem adresu email.

W tym wpisie chciałbym pokazać jak można przy wykorzystaniu klas z przestrzeni nazw System.ComponentModel.DataAnnotations zrealizować mechanizm walidacji w aplikacji. Muszę przyznać, jak pierwszy raz spotkałem się z tym podejściem, to od razu bardzo mi się spodobało.

Zanim przejdziemy do dodania walidacji w aplikacji zastanówmy się, w którym miejscu najlepiej walidować dane przychodzące od użytkownika. Pierwsza myśl może być taka: walidujmy dane w interfejsie użytkownika. Pomysł dobry bo użytkownik od razu będzie widział, czy dane podał poprawne, czy nie. Niestety tutaj problemem jest taka sytuacja, w której użytkownik na przykład nie skorzysta z naszego interfejsu i wyśle odpowiednio spreparowane żądanie do serwera. Co wtedy? Dlatego powinniśmy też walidować dane przychodzące do akcji, czy są poprawne. No i do tego dobrze je walidować na poziomie interfejsu, aby użytkownik wiedział co się dzieje.  Dlatego warto w tych dwóch miejscach walidować dane przychodzące od użytkownika.

Na pewno teraz sobie myślisz, że głupotą jest trzymanie tych samych reguł walidacyjnych w dwóch różnych miejscach, szczególnie, że jak coś będziemy chcieli zmienić, będziemy musieli edytować reguły w dwóch miejscach. Zapewne sobie myślisz, czy nie ma lepszego rozwiązania? A czemu reguł tych nie zapisać w naszym modelu i wykorzystywać ich w reszcie aplikacji? Tutaj właśnie z pomocą przychodzą nam klasy z przestrzeni nazw System.ComponentModel.DataAnnotations. Dzięki tym klasą możemy sobie zdefiniować reguły walidacyjne na poziomie modelu, a następnie ASP.NET MVC 2 praktycznie same z nich będzie korzystać.

No dobra ale jak to działa? W naszej przykładowej aplikacji mamy jedną kasę modelu – GuestBook. Dla przypomnienia nasza klasa ma takie o to właściwości:

  • Id – wymagane i automatycznie uzupełniana przez Linq To Sql
  • Nick – wymagane, a w bazie jest ustawiony limit na 50 znaków
  • Text – wymagane
  • Email – nie wymagane, w bazie jest limit na 150 znaków oraz email powinien mieć odpowiedni format
  • AddDate – wymagane, powinna być to data

Aby skorzystać z powyższego mechanizmu walidacji, wystarczy udekorować wybrane właściwości odpowiednimi atrybutami. Dostępna lista atrybutów to:

  • Required – zapewnia, że właściwość zostanie uzupełniona
  • StringLength – zapewnia, że string będzie miał odpowiednią długość
  • Range – zapewnia, że wartość będzie z podanego przedziału
  • DataType – zapewnia, że właściwość będzie określonego typu (np. że będzie numerem telefonu lub adresem url) – definiuje to typ wyliczeniowy DataType
  • RegularExpression – umożliwia skorzystania z wyrażenia regularnego do walidacji danych
  • CustomValidation – umożliwia skorzystania z własnej metody z jakieś klasy to walidacji danych

Jak już wiemy, jakie do dyspozycji mamy atrybuty i jak mniej więcej z nich korzystać wystarczy ich teraz użyć. Niestety w tym momencie napotkamy problem: nasza klasa GuestBook jest wygenerowana przez Linq To Sql i gdy zmienimy coś na w naszym modelu (np. dodamy kolejną tabelę z bazy) to wprowadzone atrybuty w wygenerowanym pliku zostaną usunięte. Ale na szczęście jest sposób jak to obejść: Po pierwsze można zauważyć, że klasa GuestBook jest klasą patrial, czy że jej definicja może znajdować się w kilku plikach, co wykorzystamy. Nie możemy w innym pliku dodać tych samych właściwości do klasy GuestBook z odpowiednimi atrybutami. Możemy natomiast utworzyć specjalną klasę, w której będą zapisane nasze reguły i klasę tą wykorzystać jako metadane dla klasy wygenerowanej przez Linq To Sql. A zatem bierzmy się do roboty.

Pierw utwórzmy naszą klasę, która będzie opisywać reguły walidacyjne. Nazwijmy sobie ją GuestBookValidation i zdefiniujmy w niej wszystkie właściwości wraz z atrybutami walidacyjnymi. Poniżej znajduje się kod klasy GuestBookValidation:

   1: [Bind(Exclude = "Id")]
   2: class GuestBookValidation
   3: {
   4:     [Required(ErrorMessage = "Wprowadź nick")]
   5:     [StringLength(50, ErrorMessage = "Nick nie może być dłuższy niż 50 znaków")]
   6:     public string Nick { get; set; }
   7:  
   8:     [Required(ErrorMessage = "Wprowadź wpis")]
   9:     public string Text { get; set; }
  10:  
  11:     [RegularExpression("\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*", ErrorMessage = "Niepoprawny format emaila")]
  12:     [StringLength(150, ErrorMessage = "Nick nie może być dłuższy niż 50 znaków")]
  13:     public string Email { get; set; }
  14: }

Nie będę szczegółowo opisywał poszczególnych atrybutów, myślę, że są one dość jasne. Z powyższego kodu wspomnę tylko o dwóch rzeczach: każdy z atrybutów ma właściwość ErrorMessage, która zostanie użyta do wyświetlenie użytkownikowi, gdy dana właściwość nie będzie się walidować. Drugą rzeczą to właściwość całej klasy Bind. Za jego pomocą mówimy kompilatorowi, że nie chcemy, aby wiązał on właściwości Id z GuestBook z właściwościami klasy GuestBookValidation. Wszystkie pozostałe właściwości zostaną połączone i zostaną wykorzystane reguły walidacyjne z klasy GuestBookValidation w klasie GuestBook.

Aby wszystko ładnie działało pozostaje tylko powiedzieć, żeby klasa GuestBook korzystała z klasy GuestBookValidation jako klasy z metadanymi. W tym celu tworzymy korzystamy z tego, że klasa GuestBook jest klasą patrial i gdzieś w projekcie (najlepiej obie klasy wrzucić do katalogu Models) wrzucamy coś takiego:

   1: [MetadataType(typeof(GuestBookValidation))]
   2: public partial class GuestBook
   3: {
   4: }

I już możemy cieszyć się z walidacji Smile

Zobaczmy jak teraz działa formularz dodania nowego wpisu. Gdy klikniemy w przycisk Create bez wypełnionych pól to zobaczymy coś takiego:

image

Czyli jak widać walidacja działa, a do tego wyświetlają się odpowiednie komunikaty.

No dobra walidacja działa fajnie, tylko fajnie by było, jak by się formularz walidował przed wysłaniem danych do serwera, aby walidacja odbywała się za pomocą java scriptu. Na szczęście ASP.NET MVC 2 jest nam tutaj bardzo pomocne i bardzo łatwo można to zrealizować. Wystarczy dodać do widoku Create (np. tuż przed formularzem) coś takiego:

   1: <script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
   2: <script src="/Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script>
   3: <%Html.EnableClientValidation(); %>
I możemy się cieszyć walidacją po stronie klienta, prawda, że fajne? Smile Tags: , ,
Categories: Techniczne

Permalink E-mail | Kick it! | DZone it! | del.icio.us Komentarze (0) Post RSSRSS comment feed

Tworzenie widoków w ASP.NET MVC 2

W poprzednich dwóch wpisał pokazałem jak można stworzyć model oraz kontroler dla naszej przykładowej aplikacji ASP.NET MVC 2. W tym wpisie chciałbym pokazać jak stworzyć widoki dla księgi gości. Widoki tutaj przedstawione będę dość proste. W późniejszej części serii artykułów postaram się je bardziej rozbudować.

Tak jak wcześniej opisywałem sposób działania aplikacji ASP.NET MVC jest następujący: użytkownik wysyła jakieś żądanie do serwera www, następnie jest wybierany kontroler oraz akcja, która ma się wykonać. Sama akcja na ogół wyciąga jakieś dane z modelu oraz wyświetla odpowiedni widok. Domyślna konwencja przyjętą w ASP.NET MVC zakłada, że domyślnie wyświetlany jest widok z katalogu Views, katalogu odpowiedniego dla kontrolera oraz identycznej nazwie jak akcja. Dla przykładu, jeśli mamy kontroler GuestBookController, a w nim akcję Index, to domyślnie dla tej akacji (gdy wywołamy metodę View) zostanie użyty widok Index z katalogu Views\GuestBook. Metoda View ma kilka przeciążonych metod i nie musimy koniecznie korzystać z powyższej konwencji i możemy wyświetlić dowolny widok. Ale zaproponowane rozwiązanie jest wygodne.

Jak zatem wygenerować widok dla określonej akcji? Na szczęście Visual Studio bardzo nam w tym pomaga i większość rzeczy robi za nas. Ady dodać widok do akcji Index kontrolera GuestBookController, wystarczy w ciele akcji kliknąć prawym klawiszem myszy i wybrać Add View. Poniżej znajduje się okno jak wyświetli się nam w celu dodania nowego widoku:

image

A w nim możemy ustawić kilka właściwości, które spowodują różne wygenerowanie nam widoku. Możemy sobie nadać własną nazwę widoku, najlepiej pozostawić domyślnie wygenerowaną. W większości wypadku warto sobie zaznaczyć checkboxa Create a strongly-typed view. Opcja ta spowoduje je nasz widok będzie silnie typowany, a z listy poniżej możemy sobie wybrać klasę z jaką chcemy pracować. W przykładzie jest to klasa GuestBook, która została wygenerowana przez Linq To Sql. Co nam to daje? Po pierwsze to, że możemy skorzystać sobie z predefiniowanych szablonów widoku (na rysunku jest to widok List), dzięki czemu Visual Studio na podstawie obiektu wygeneruje nam odpowiedni widok dla każdej publicznej właściwości naszego obiektu. W przykładzie będzie to tabela, której kolumnami będą właściwości naszego obiektu GuestBook. Dostępne szablony zostaną opisane w dalszej części artykułu.

Ostatnim elementem jaki możemy zdefiniować dla nowego widoku to, czy ma korzystać z master page, a jeśli tak to jakiego.

Po kliknięciu Add, Visual Studio wygeneruje nowy widok dla akcji Index. I jak można zobaczyć Visual Studio wygenerowało nam kod, który spowoduje wyświetlenie tabeli na stronie. Co widać poniżej na listingu:

 

   1: <h2>Index</h2>
   2:  
   3: <table>
   4:     <tr>
   5:         <th></th>
   6:         <th>
   7:             Id
   8:         </th>
   9:         <th>
  10:             Nick
  11:         </th>
  12:         <th>
  13:             Text
  14:         </th>
  15:         <th>
  16:             Email
  17:         </th>
  18:         <th>
  19:             AddDate
  20:         </th>
  21:     </tr>
  22:  
  23: <%
   1:  foreach (var item in Model) { 
%>
  24:  
  25:     <tr>
  26:         <td>
  27:             <%
   1: : Html.ActionLink("Edit", "Edit", new { id=item.Id }) 
%> |
  28:             <%
   1: : Html.ActionLink("Details", "Details", new { id=item.Id })
%> |
  29:             <%
   1: : Html.ActionLink("Delete", "Delete", new { id=item.Id })
%>
  30:         </td>
  31:         <td>
  32:             <%
   1: : item.Id 
%>
  33:         </td>
  34:         <td>
  35:             <%
   1: : item.Nick 
%>
  36:         </td>
  37:         <td>
  38:             <%
   1: : item.Text 
%>
  39:         </td>
  40:         <td>
  41:             <%
   1: : item.Email 
%>
  42:         </td>
  43:         <td>
  44:             <%
   1: : String.Format("{0:g}", item.AddDate) 
%>
  45:         </td>
  46:     </tr>
  47:  
  48: <%
   1:  } 
%>
  49:  
  50: </table>
  51:  
  52: <p>
  53:     <%
   1: : Html.ActionLink("Create New", "Create") 
%>
  54: </p>
W oczy się rzuca, że html jest przeplatany na zmianę z znacznikami <% %>. W znacznikach tych możemy zawierać kod c#, który zostanie wykonany podczas generowania widoku. Znacznik ten ma dwie postacie: <% %> oraz <%: %>. Pierwsza służy do kodu, który nie zwraca nic do generowanego htmla (na przykład może być to kod jakieś pętli). Drugi służy do przekazania do htmla jakiegoś ciągu znaków. W przykładzie może być to np. wygenerowany link do jakiegoś akcji przez metodę ActionLink klasy Html. O klasie Html będzie dokładniej w jednym z późniejszych artykułów serii.

Mając już tak wygenerowany widok pozostaje zobaczyć nam, czy wszystko działa ok. W tym celu uruchamiamy aplikację za pomocą klawiszu F5. Po uruchomieniu zobaczymy stronę główną naszej aplikacji, która została wygenerowana przez Visual Studio podczas tworzenia aplikacji ASP.NET MVC 2.

Jak w takim razie zobaczyć to co zrobiliśmy? Domyślna konwencja mówi, że aby wykonać jakąś akcję z kontrolera należy użyć adresu url o podanej budowie: adres.strony.pl/kontroler/akcja. Gdzie za kontroler wpisujemy nazwę kontrolera (bez końcówki Controller), a za akcję nazwę żądanej akcji. I tak url adres.strony.pl/GuestBook/Index spowoduje wyświetlenie wcześniej wygenerowanego widoku tabeli wszystkich wpisów w księdze gości. Mechanizm ten nazywa się routingiem. Dokładniej routing opiszę w jednym z kolejnych artykułów.

Po wyświetleniu akcji Index z kontrolera GuestBookController zobaczymy taki widok i ile wcześniej nic nie dodaliśmy do bazy danych.

image

Jak widać lista wpisów jest pusta. Natomiast tabela zawiera wszystkie kolumny z naszej tabeli z bazy danych. Dodatkowo został dodany link Create New, który spowoduje wykonanie akcji Create (związanej z żądaniem get, czyli wyświetlenie formularza dodania nowego wpisu) z kontrolera GuestBookController. Kliknięcie w ten link teraz spowoduje wyświetlenie wyjątku, który informuje, że nie ma wygenerowanego widoku dla akcji Create. Dlatego przejdźmy teraz do jego wygenerowania.

Widok dla akcji Create generuje się podobnie jak dla akcji Index. Tylko z tą różnicą, że zamiast wybrania szablonu List, wystarczy wybrać szablon Create. W wygenerowanym widoku warto wykonać kilka zmian:

  • Usunąć z formularza wpisanie przez użytkownika Id oraz daty dodania
  • Dla pola Text zmienić generowany textbox na TextArea

Po tych zmianach kod widoku powinien wyglądać tak:

   1: <h2>Create</h2>
   2:  
   3: <% using (Html.BeginForm()) {%>
   4:     <%: Html.ValidationSummary(true) %>
   5:  
   6:     <fieldset>
   7:         <legend>Fields</legend>
   8:         
   9:         <div class="editor-label">
  10:             <%: Html.LabelFor(model => model.Nick) %>
  11:         </div>
  12:         <div class="editor-field">
  13:             <%: Html.TextBoxFor(model => model.Nick) %>
  14:             <%: Html.ValidationMessageFor(model => model.Nick) %>
  15:         </div>
  16:         
  17:         <div class="editor-label">
  18:             <%: Html.LabelFor(model => model.Text) %>
  19:         </div>
  20:         <div class="editor-field">
  21:             <%: Html.TextAreaFor(model => model.Text) %>
  22:             <%: Html.ValidationMessageFor(model => model.Text) %>
  23:         </div>
  24:         
  25:         <div class="editor-label">
  26:             <%: Html.LabelFor(model => model.Email) %>
  27:         </div>
  28:         <div class="editor-field">
  29:             <%: Html.TextBoxFor(model => model.Email) %>
  30:             <%: Html.ValidationMessageFor(model => model.Email) %>
  31:         </div>                     
  32:         
  33:         <p>
  34:             <input type="submit" value="Create" />
  35:         </p>
  36:     </fieldset>
  37:  
  38: <% } %>
  39:  
  40: <div>
  41:     <%: Html.ActionLink("Back to List", "Index") %>
  42: </div>

Natomiast widok po wyświetleniu powinien wyglądać mniej więcej tak:

image

Na razie nie ma walidacji i jak klikniemy w przycisk Create to wyświetli się nam informacje o błędzie. Walidację dodamy później w jednym z kolejnych artykułów.

Gdy wypełnimy poprawnie formularz oraz klikniemy w przycisk Create to nasz wpis zostanie dodany do bazy danych, co zobaczymy na liście wszystkich wpisów, wygenerowanej przez akcję Index kontrolera GuestBook.

Pozostałe widoki generuje się analogicznie do dwóch powyższych, z tą różnicą, że korzysta się z różnych szablonów. Dostępne szablony to:

  • Create – tworzy formularz do dodania nowego obiektu
  • Delete – formularz, w którym użytkownik potwierdza, że chce usunąć dany obiekt
  • Details – szczegółowe informacje o obiekcie (tylko do odczytu)
  • Edit – formularz do edycji obiektu
  • Empty – pusty widok
  • List – tabela z listą obiektów (kolumny to ich właściwości)
Tags: , ,
Categories: Techniczne

Permalink E-mail | Kick it! | DZone it! | del.icio.us Komentarze (0) Post RSSRSS comment feed

Boxing oraz typy wartościowe

Ostatnio pokazałem poniższy kod kolegą, z pytaniem co się pojawi na konsoli. Kod wyglądał tak:

   1: int a = 10;
   2: object boxed = a;
   3: a = 5;
   4: Console.WriteLine(boxed);

Część osób odpowiedziała, że 5, a część, że 10. A jaka jest poprawna odpowiedz? Na pierwszy rzut oka mogłoby się wydać, że powinna zostać wypisana liczba 5, ponieważ typ object wskazuje na pewien obszar w pamięci i części osób może się wydać, że jest to obszar, w którym znajduje się wartość zmiennej a.

No ale tutaj wychodzi różnica między typami referencyjnymi oraz wartościowymi. A dokładniej lokalizacji w pamięci, gdzie oba rodzaje typów są przechowywane. Typy wartościowe znajdują się na stosie (tam też znajdują się referencje to typów referencyjnych). Natomiast typy referencyjne znajdują się na stercie.

W przykładzie podczas pakowania zmiennej a do typu referencyjnego następuje skopiowanie wartości z stosu na stertę (utworzony jest tam odpowiedni obiekt typu referencyjnego). Referencja boxed później wskazuje na ten obszar pamięci. Wtedy zmiana zmiennej a z stosu, nie powoduje zmiany wartości zmiennej na stercie, przez co na ekranie wyświetli się liczba 10, a nie 5.

Tags: , ,
Categories: Techniczne

Permalink E-mail | Kick it! | DZone it! | del.icio.us Komentarze (0) Post RSSRSS comment feed

Tworzenie kontrolera oraz akcji w ASP.NET MVC 2

W poprzednim wpisie przedstawiłem jak można sobie stworzyć model w aplikacji ASP.NET MVC 2 dla przykładowej aplikacji, którą jest księga gości. W tym wpisie chciałbym opisać jak do aplikacji dodać kontroler z akcjami dla naszej przykładowej aplikacji.

Ale za nim przejdę do opisania jak to zrobić, pierw kilka słów na temat kontrolerów i akcji w ASP.NET MVC 2. Kontroler to klas, która dziedziczy po abstrakcyjnej klasie System.Web.Mvc.Controller. Natomiast każda publiczna metoda (zwracająca tym ActionResult) w klasie kontrolera jest akcją, jaka może zostać wykonana w ramach jakiegoś żądania użytkownika.

Akcje mogą być przypisane do określonego typu żądania protokołu http. I tak jedna akcja np. Create może zostać przypisana do żądania typu get (domyślny typ żądania), który spowoduje wyświetlenia formularza dodania nowego wpisu do księgi gości. Natomiast inną akcję o nazwie Create (i innej sygnaturze niż poprzednia) możemy wykonywać, gdy do serwera przyjdzie żądania typu post (wtedy, gdy np. użytkownik przesyła formularz dodania nowego wpisu w księdze gości z wypełnionym polami). Dzięki temu ASP.NET MVC jest automatycznie w stanie rozpoznać typ żądania i odpowiednio uruchomić właściwą akcję.

Tak jak napisałem domyślnym typem żądania jest żądanie get i aby obsłużyć taki typ żądania nic nie musimy robić. Natomiast, gdy chcemy aby akcja wykonała się w ramach innego typu żądania (np. post) musimy akcję oznaczyć odpowiednim atrybutem. Dostępne atrybuty to:

  • HttpDelete
  • HttpGet
  • HttpPost
  • HttpPut

które odpowiadają odpowiednim żądaniom protokołu http.

Tak jak wspomniałem w jednym z wcześniejszych wpisów, w ASP.NET MVC wykorzystuje się konwencje nazewnicze. I tak każda klasa kontrolera powinna kończyć się słowem Controller. Na szczęście Visual Studio bardzo nam w tym względzie pomaga i sam to podpowiada.

A więc jak stworzyć nowy kontroler? Nic trudnego, klikamy prawym klawiszem mysz na folder Controllers i wybieramy Add-> Controller. Pojawi się okienko, które widać poniżej:

image

W powyższym oknie możemy nadać nazwę kontrolerowi oraz zaznaczyć jednego checkboxa. Jak zaznaczymy go, to Visual Studio automatycznie wygeneruje nam akcje dla takich scenariuszy jak: dodanie nowego obiektu, edycja, usunięcie oraz wyświetlenie szczegółów. Jest to o tyle przydatne, gdy tworzymy akcje dla operacji typu CRUD to Visual Studio zaoszczędzi nam sporo pracy.

Po kliknięciu w przycisk Add, możemy cieszyć się naszym nowym kontrolerem.

Teraz pozostaje nam oprogramowanie poszczególnych akcji kontrolera.

Zacznijmy od akcji Index, która spowoduje wyświetlenie listę wszystkich wpisów w księdze gości. Kod akcji Index może wyglądać między innymi tak:

   1: public ActionResult Index()
   2: {
   3:     DB db = new DB();
   4:     return View(db.GuestBooks);
   5: }

W linijce 3 tworzymy nowy obiekt klasy DB, za pomocą której będziemy wyciągać dane z bazy danych. Natomiast w kolejnej linijce jest wywoływana metoda View, który utworzy odpowiedni widok (o czym będzie w kolejnym artykule) i przekazana do niego zostanie kolekcja obiektów klasy GuestBook, w której będą wszystkie wpisy z księgi gości.

Kolejną akcją jest akcje Details, która wyświetla szczegóły dla dane wpisu (w przypadku księgi gości nie ma ona jakiegoś większego sensu, ale zwarłem go tak dla kompletnego opisu wszystkich akcji wygenerowanych przez Visual Studio).

   1: public ActionResult Details(int id)
   2: {
   3:     DB db = new DB();
   4:  
   5:     var guestBook = db.GuestBooks.Where(x => x.Id == id).FirstOrDefault();
   6:  
   7:     if (guestBook == null)
   8:     {
   9:         RedirectToAction("Index");
  10:     }
  11:  
  12:     return View(guestBook);
  13: }

Co pierwsze rzuca się w oczy to, że akcja Details przyjmuje parametr typu int, który jest id wpisu, które trzeba wyświetlić szczegóły. ASP.NET MVC automatycznie zamapuje parametry żądania get na argument akcji (jak to wszystko działa zostanie opisane w późniejszym artykule).

W ciele akcji Details podobnie jak w akcji Index tworzony jest obiekt DB. Następnie z kolekcji wszystkich wpisów jest wybierany wpis o danym id (wybieranie odbywa się za pomocą metody Where i wyrażenia lambda, które mówi, że przekazany argument do metody należy porównywać z właściwością Id obiektu GuestBook). Wywołanie metody FirstOrDefault spowoduje zwrócenie do zmiennej guestBook obiektu GuestBook o danym Id, o ile znajduje się w bazie. W przeciwnym wypadku, gdy nie ma wpisu o danym id zwrócony zostanie null.

Następie w ifie sprawdzany, czy w bazie istnieje wpis o danym id (przez porównanie zmiennej guestBook z nullem). Gdy wpisu nie ma za pomocą metody RedirectToAction przechodzimy do akcji Index. Natomiast, gdy wpis o id jest w bazie tworzymy odpowiedni widok i przekazujemy obiekt guestBook do niego.

Teraz przejdźmy do dwóch akcji odpowiedzialnych za dodanie nowego wpisu w księdze gości. Czemu dwóch? Tak jak napisałem na początku ASP.NET MVC rozpoznaje typ żądania http jaki przychodzi do serwera i jest na jego podstawie wykonać różne akcje. Tutaj można to sobie fajnie wykorzystać. Jedna akcja Create (która będzie wykonywała się podczas żądania get) spowoduje wyświetlenie formularza dodania nowego wpisu do księgi gości. Natomiast druga akcja Create (przypisana do żądania post oraz przyjmująca parametr) zostanie wywołana, gdy do serwera przyjdzie żądanie post z wypełnionym formularzem przez użytkownika.

Kod obu akcji widać poniżej:

   1: public ActionResult Create()
   2: {
   3:     return View();
   4: } 
   5:  
   6: [HttpPost]
   7: public ActionResult Create(GuestBook guestBook)
   8: {
   9:     if (ModelState.IsValid)
  10:     {
  11:         try
  12:         {
  13:             DB db = new DB();
  14:             guestBook.AddDate = DateTime.Now;
  15:             db.GuestBooks.InsertOnSubmit(guestBook);
  16:             db.SubmitChanges();
  17:  
  18:             return RedirectToAction("Index");
  19:         }
  20:         catch
  21:         {
  22:             return View("Error");
  23:         }
  24:     }
  25:     else
  26:     {
  27:         return View(guestBook);
  28:     }
  29: }

Pierwsza akcja Create jest bardzo prosta. Po prostu wyświetla odpowiedni widok.

Druga jest już dużo bardziej skomplikowana. Pierwszą rzeczą jaka rzuca się w oczy to dodany atrybut HttpPost przed akcją. Co jak już wcześniej pisałem spowoduje przypisanie akcji to żądania post.

Uważny czytelnik, który na bieżąco wykonuje opisywane czynności w Visual Studio może zauważyć, że argument akcji Create w listingu powyżej jest inny, niż w tym co wygenerowało Visual Studio. Visual Studio wygenerowało taki kod:

   1: public ActionResult Create(FormCollection collection)

Gdzie przekazanym argument to obiekt klasy FormCollecion, który reprezentuje wszystkie wartości przekazanego formularza. Obiekt tej jest zwykłym słownikiem i możemy się do niego odwoływać za pomocą kluczy, którymi są nazwy poszczególnych pól formularza, np:

   1: string nick = collection["Nick"];

Dla nas programistów c# takie podejście jest fu. My lubimy silną kontrolę typów, a nie pracę ze słownikiem i typem object. Dodatkowo z takim podejściem nie będziemy mogli skorzystać sobie z fajnej walidacji (o której będzie w którymś z kolejnych artykułów).

Na szczęście ASP.NET MVC 2 jest fajne i potrafi na podstawie nazw pól formularza zamapować nam formularz z właściwościami jakiegoś obiektu, w naszym przypadku obiektu klasy GuestBook. Dzięki czemu w akcji Create wygenerowanej przez Visual Studio możemy sobie zamienić FormCollection collection na GuestBook guestBook.

Główny if może się wydać nam trochę dziwny (o nim będzie jeszcze trochę w dalszym ciągu serii). Ale szybko tłumacząc to sprawdza on, czy ASP.NET MVC dobrze zamapowało dane z formularza do obiektu klasy GuestBook. Jeśli nie to zostanie wyświetlony formularz dodania nowego wpisu do księgi gości z już wypełnionymi danymi, które znajdowały się wcześniej w formularzu. Do tego jeszcze wrócę dlaczego tak, gdy będę opisywał walidację.

Gdy ASP.NET dobrze zamapowało dane z formularza do obiektu GuestBook, następuje dodanie go do bazy danych. Wcześniej przed samym dodaniem następuje ustawienie dany dodania wpisu na aktualną datę. Po zapisaniu wpisu w bazie następuje przekierowanie do akcji Index.

Jeśli podczas dodania wpisu do bazy danych nastąpił jakiś błąd i został wyrzucony wyjątek, zostanie on złapany przez blok try-catch i użytkownikowi zostanie wyświetlony widok Error z informacją o błędzie.

Kolejnymi akcjami naszego kontrolera, będą akcje odpowiedzialne za edycję wpisu w księdze gości. Tutaj nie będę opisywał jak zabezpieczyć wykonanie akcji, tak aby mogli je wykonać użytkownicy o roli administratora. Opiszę to w jednym z późniejszych artykułów w serii.

Podobnie jak w przypadku dodawania nowego wpisu, tak i przy edycji wpisów będziemy mieli dwie akcje Edit, przypisane do różnych żądań http – get i post. Kod akcji znajduje się poniżej:

   1: public ActionResult Edit(int id)
   2: {
   3:     DB db = new DB();
   4:  
   5:     var guestBook = db.GuestBooks.Where(x => x.ID == id).FirstOrDefault();
   6:  
   7:     if (guestBook == null)
   8:     {
   9:         return RedirectToAction("Index");
  10:     }
  11:  
  12:     return View(guestBook);
  13: }
  14:  
  15: [HttpPost]
  16: public ActionResult Edit(int id, FormCollection  collection)
  17: {
  18:     try
  19:     {
  20:         DB db = new DB();
  21:         var guestBook = db.GuestBooks.Where(x => x.ID == id).FirstOrDefault();
  22:  
  23:         if (guestBook == null)
  24:         {
  25:             return RedirectToAction("Index");
  26:         }
  27:  
  28:         UpdateModel(guestBook, collection.ToValueProvider());
  29:         db.SubmitChanges();
  30:  
  31:         return RedirectToAction("Index");
  32:     }
  33:     catch
  34:     {
  35:         return View("Error");
  36:     }
  37: }

Pierwsza akcja Edit jest identyczna jak akcja Details, dlatego nie będę jej opisywać. Natomiast początek drugiej akcji Edit jest bardzo podobny do cała akcji Edit dla żądania get. Różnica zaczyna się, gdy już wyciągniemy obiekt z bazy danych, którego ma nastąpić edycja.

Jak można zauważyć druga akcje Edit przyjmuje podobnie jak akcje Create obiekt FormCollection. Niestety nie możemy sobie postąpić podobnie jak w akcji Create i zdać na automatyczne mapowanie ASP.NET MVC na poziomie wywoływania akcji. Spowodowane jest to tym, że nie moglibyśmy zmienić w bazie danych wpisu na podstawie tak utworzonego obiektu GuestBook, ponieważ nie jest on przypisany do żadnego obiektu DB. Na szczęście twórcy ASP.NET MVC ułatwili nam zadanie i do frameworka dodali metodę UpdateModel, która na podstawie obiektu wyciągniętego z bazy (guestBook) oraz danych z formularza automatycznie zaktualizuje obiekt naszego modelu. Następnie wystarczy tylko zapisać zmiany w bazie i przekierować użytkownika na stronę z wszystkimi wpisami w księdze.

W przypadku wystąpienia jakiegoś błędu podobnie jak w akcji Create, zostanie wyświetlony widok Error dla użytkownika z informacją o błędzie.

No i na koniec zostaje nam opisanie akcji usuwania wpisu (podobnie jak w przypadku akcji Edit zabezpieczenie akcji przed wywołaniem przez niepożądaną osobę opiszę w jednym z kolejnych wpisów). Akcja Delete przypisana do żądania get wyświetla formularz, w którym użytkownik musi potwierdzić chęć usunięcia wpisu. Natomiast akcja Delete przypisana do żądania post usuwająca wpis. Obie akcje są bardzo podobne do już wcześniejszych akcji. Wystarczy rzucić okiem na kod i wszystko jest jasne Smile

   1: public ActionResult Delete(int id)
   2: {
   3:         DB db = new DB();
   4:  
   5:         var guestBook = db.GuestBooks.Where(x => x.Id == id).FirstOrDefault();
   6:  
   7:         if (guestBook == null)
   8:         {
   9:             return RedirectToAction("Index");
  10:         }
  11:  
  12:         return View(guestBook);
  13: }
  14:  
  15: [HttpPost]
  16: public ActionResult Delete(int id, FormCollection collection)
  17: {
  18:     try
  19:     {
  20:         DB db = new DB();
  21:  
  22:         var guestBook = db.GuestBooks.Where(x => x.Id == id).FirstOrDefault();
  23:  
  24:         if (guestBook == null)
  25:         {
  26:             return RedirectToAction("Index");
  27:         }
  28:  
  29:         db.GuestBooks.DeleteOnSubmit(guestBook);
  30:         db.SubmitChanges();
  31:  
  32:         return RedirectToAction("Index");
  33:     }
  34:     catch
  35:     {
  36:         return View();
  37:     }
  38: }

Podobnie jak w akcjach wcześniejszych na początku obu akcji jest wyciągany wpis z bazy o danym id. Jeśli nie ma takiego, użytkownik jest przekierowywany do akcji Index. Natomiast, gdy jest pierwsza akcja wyświetla formularz, natomiast w drugiej następuje usunięcie go z bazy danych i przekierowanie użytkownika do akcji Index. W przypadku wystąpienia błędu wyświetla się użytkownikowi stosowane informacja o błędzie.

To by było na tyle z podstaw tworzenia kontrolerów w ASP.NET MVC 2. W późniejszych artykułach opiszę trochę bardziej zaawansowane rzeczy o kontrolerach. Natomiast w następnym wpisie będzie na temat widoków w ASP.NET MVC.

Tags: , ,
Categories: Techniczne

Permalink E-mail | Kick it! | DZone it! | del.icio.us Komentarze (8) Post RSSRSS comment feed

Inicjalizacja obiektów w c#

Zastanawialiście się, a może wiecie jak wygląda inicjacja obiektów w c#? Co w jakiej kolejności jest wykonywane? Rozważmy przykład jak na poniższym listingu oraz załóżmy, że tworzymy obiekt klasy B. Co wykona się pierwsze? A co ostatnie?

   1: public class A
   2: {
   3:     int x = 0;
   4:     public A(int x)
   5:     {
   6:         ...
   7:     }
   8: }
   9: public class B : A
  10: {
  11:     int y = 0;
  12:     public B(int x)
  13:         :base(x + 100)
  14:     {
  15:         ...
  16:     }
  17: }

W c# inicjacja obiektów przebiega następująco:

  1. Z klasy potomnej do bazowej
    1. Pola klasy są inicjowane
    2. Obliczane są argumenty przekazywane do konstruktorów klas bazowych
  2. Z klasy bazowej do potomnej
    1. Wykonywany jest kod konstruktorów

W przykładzie kod będzie wykonywany w następującej kolejności (podane numery to numery wiersza z listingu): 11, 13, 3, 6 oraz 15. Prawda, że proste? Smile

Tags:
Categories: Techniczne

Permalink E-mail | Kick it! | DZone it! | del.icio.us Komentarze (0) Post RSSRSS comment feed

Tworzenie modelu dla aplikacji ASP.NET MVC 2

Mając już wygenerowany projekt aplikacji ASP.NET MVC pierwszą rzeczą jaką powinniśmy zrobić to stworzenie modelu dla naszej aplikacji. W niniejszym wpisie postaram się opisać jak można to zrobić.

Tak jak pisałem wcześniej w ramach serii artykułów postaram się zbudować prostą księgę gości. Dane jakie chciałbym przechowywać to:

  • Nick osoby, która zostawia wpis
  • Email osoby zostawiającej wpis
  • Treść wpisu
  • Datę dodania wpisu

Aby za bardzo nie rozbudowywać przykładu dane te będę przechowywał w bazie danych znajdującej się w pliku w katalogu App_data aplikacji. Natomiast w dostępie do danych wykorzystam technologię Linq To Sql.

Aby dodać bazę do projektu, wystarczy kliknąć prawym myszy na katalog App_data i tam wybrać Add->New Item. W okienku, które się pojawi wybieramy SQL Server Database, nadajemy nazwę plikowi (np. GuestBook.mdf) i klikamy Add. Okienko widać na rysunku niżej:

image

Po utworzeniu pliku będzie on znajdował się w katalogu App_data, co widać poniżej:

image

Teraz wystarczy dwa razy kliknąć na plik, aby połączyć się z bazą i za pomocą Visual Studio edytować jej strukturę oraz dane. Otworzy się nam okienko Server Explorer, a w nim sekcji Data Connections nasza wcześniej utworzona baza danych (rysunek niżej):

image

Teraz wystarczy tylko dodać tabelę do naszej bazy. W tym celu klikamy prawym przyciskiem na katalog Tables i wybieramy Add New Table. Pojawi się nam okno, w którym możemy zdefiniować strukturę tabeli. Struktura tabeli to:

image

Ważne, aby dla kolumnę Id uczynić kluczem głównym oraz ustawić dla niej autonumerowanie. Aby to zrobić z okna poniżej Column Properties odnaleźć sekcję Identity Specification i tam ustawić właściwość Id Identity na Yes. Pozostałe dwie opcje to wartość o jaką jest zwiększana za każdym razem wartość kolumny oraz wartość początkowa.

image

Tak utworzoną tabelę pozostaje nam zapisać i nadać jej nazwę np. GuestBook.

image

Mając już stworzoną bazę danych pozostaje nam skorzystanie z Linq To Sql, aby wygenerować klasy dostępowe do danych z bazy. W tym celu do katalogu Models dodajemy plik Linq To Sql, za pomocą okna Add New Item.

image

Na nową powstałą formatkę przeciągamy tabelę GuestBook z Server Explorera.

image

W okienku Properties dla całej formatki warto zmienić sobie kilka właściwości:

image

Poszczególne właściwości, które warto zmienić (na rysunku powyżej pogrubione) to:

  • Context Namespace – przestrzeń nazw, w której znajdować się będzie klasa DB, za pomocą której będą następowały operacje na bazie danych
  • Entity Namespace – przestrzeń nazw, w której znajdować się będą obiekty wygenerowane na podstawie tabel (w przykładzie klasa GuestBook wygenerowana na podstawie tabeli GuestBook)
  • Name – nazwa klasy, za pomocą której będą następowały operacje na bazie danych

Po zapisaniu pliku możemy już korzystać z wygenerowanej warstwy dostępu do danych, z której jak korzystać opiszę w następnym artykule poświęconym kontrolerom.

Tags: ,
Categories: Techniczne

Permalink E-mail | Kick it! | DZone it! | del.icio.us Komentarze (1) Post RSSRSS comment feed

Słowo kluczowe checked

Jak sądzisz co się stanie, gdy wykona się poniższy kod?

   1: int a = int.MinValue;
   2: a--;
   3: Console.WriteLine(a == int.MaxValue);

Jeśli sądzisz, że zostanie wyrzucony wyjątek to się mylisz. Natomiast jeśli sądzisz, że wyświetli się true to masz rację Smile

A co się stanie, gdy powyższy kod wrzucimy w klauzurę checked? Zapewne sobie myślisz, że stanie się coś innego. Masz rację. W tym wypadku zostanie wyrzucony wyjątek OverflowException, z komunikatem “Arithmetic operation resulted in an overflow”, czyli zostaniemy poinformowani, że nastąpiło przepełnienie.

Domyślnie Visual Studio kompiluje program tak, aby nie nastąpiło sprawdzanie, czy nastąpiło przepełnienie. Jest to związane z wydajnością, po prostu nie sprawdzanie działa szybciej, a w większości przypadków jest ono zbędne. W przypadku, gdy spodziewamy się, że taka sytuacji może nastąpić, powinno się skorzystać z słowa kluczowego checked oraz sprawdzić, czy nie został wyrzucony wyjątek OverflowException.

A co w przypadku, gdy w naszej aplikacji możliwość przepełniania jest czynnością bardzo częstą? W każdym miejscu mamy używać słowa chceked? Odpowiedz brzmi nie. Istnieje możliwość tak skompilowania aplikacji (dodanie przełącznika /chceked), aby domyślnie wszystkie operacja arytmetyczne były sprawdzane pod względem przepełniania.

A jak zrobić to w naszym ulubionym ide? W Visual Studio wystarczy wejść do właściwości projektu, następnie do zakładki Build. Tam odszukujemy przycisk Advanced i tam zaznaczymy checkboxa przy opcji Check for arithmetic overflow/underflow. Co widać na rysunku niżej:

image

A co, gdy skompiluje program z przełącznikiem chceked, a nie chcę mieć sprawdzania, czy wystąpiło przepełnienie? Na szczęście w takiej sytuacji projektanci c# dali nam możliwość skorzystania z słowa kluczowego unchecked, które wykorzystujemy podobnie jak słowo chceked Smile

Tags: ,
Categories: Techniczne

Permalink E-mail | Kick it! | DZone it! | del.icio.us Komentarze (0) Post RSSRSS comment feed

Tworzenie projektu ASP.NET MVC 2 oraz jego struktura

Pracę z ASP.NET MVC 2 rozpoczyna się od utworzenia nowego projektu. Standardowo w Visual Studio wybieramy File->New->Project (lub korzystam z kombinacji klawiszy Crtl + Shift + N). W Visual Studio 2010 w sekcji Web mamy standardowo do wyboru dwa typy projektów ASP.NET MVC 2: ASP.NET MVC 2 Web Application oraz ASP.NET MVC 2 Empty Web Application, co widać na rysunku poniżej:

image

Czym różnią się oba szablony projektów? Drugi jak sama nazwa mówi tworzy pusty szablon projektu ASP.NET MVC 2. Natomiast w pierwszym szablonie na początku mamy stworzoną prostą stronę ASP.NET MVC 2, która głównie zawiera mechanizm uwierzytelniania. Dzięki czemu nie musimy tego sami pisać, tylko od razu możemy z tego korzystać.

Jedną z zalet ASP.NET MVC w stosunku do klasycznego ASP.NET jest to, że ASP.NET MVC umożliwia łatwe testowanie aplikacji za pomocą testów jednostkowych i ogólnie tworzenie aplikacji zgodnie z metodyką TDD. Dlatego podczas tworzenia nowego projektu ASP.NET MVC Visual Studio pyta się, czy ma wygenerować specjalny projekt dla testów jednostkowych. Co widać na rysunku poniżej:

image

Możemy sobie zdecydować, czy chcemy, aby Visual Studio wygenerowało testy jednostkowe. A jeśli tak to możemy zdefiniować sobie nazwę projektu oraz wybrać framework użyty do testów jednostkowych np. Visual Studio Unit Test lub NUnit.

Struktura projektu

W ASP.NET MVC bardzo ważna jest struktura projektu i konwencje w niej użyte. Na rysunku poniżej widać solution explorer dla nowo wygenerowanego projektu (szablon ASP.NET MVC 2 Web Application):

image

Na rysunku widać, że w ramach solution są dwa projekty: projekt ASP.NET MVC oraz projekt dla testów jednostkowych. Projektem testów jednostkowych zajmować się będziemy w jednym z kolejnych wpisów.

W głównym projekcie rozwiązania – projekt ASP.NET MVC – znajduje się kilka katalogów:

  • Content – w tym katalogu znajdują się różnego rodzaju pliki wykorzystywane na stronie. Pliki takiej jak grafika, pliki kaskadowych stylów itp.
  • Controllers – tutaj znajdują się klasy kontrolerów.
  • Models – tutaj znajdować się będą klasy modelu.
  • Scripts – tutaj znajdują się pliki skryptów java script. Domyślnie są dodane pliki dla biblioteki Microsoft Ajax oraz jquery.
  • Views – w tym katalogu znajdują się katalogi dla poszczególnych grupy widoków. Ważna jest konwencja nazewnicza. Nazwy katalogów odpowiadają dla nazw kontrolerów. I tak na przykładowym rysunku widać dwa kontrolery (AccountController oraz HomeController) w katalogu Controllers i odpowiadające im dwa katalogi dla widoków dostępnych dla tych kontrolerów (katalog Account oraz Home w katalogu Views). Teoretycznie konwencje można zmieniać ale jednak lepiej zostawić ją jaka jest.

Dodatkowo w katalogu Views znajduje się specjalny katalog Shared, w którym znajdują się wspólne widoki, kontroli czy master page dla wszystkich widoków z pozostałych katalogów. W przykładzie są to widok błędów, kontrolka do logowania użytkownika w aplikacji oraz główny master page.

Dwoma pozostałymi elementami projektu to plik konfiguracyjny Web.config oraz Global.asax. Pierwszy plik to plik konfiguracyjny aplikacji. W drugim natomiast znajduje się globalna klasa aplikacji, a w niej bardzo ważny routing, o którym dokładnie będzie jeszcze w jednej z części tej serii artykułów.

Tags: ,
Categories: Techniczne

Permalink E-mail | Kick it! | DZone it! | del.icio.us Komentarze (0) Post RSSRSS comment feed

New versus Virtual

C# jest językiem obiektowym, czyli możemy w nim między innymi korzystać z mechanizmu polimorfizmu. Aby to zrobić wystarczy oznaczyć funkcje w klasie bazowej słowem kluczowym virtual. A następnie w klasie dziedziczącej nadpisać metodę za pomocą słowa kluczowego override. Tak jak to widać niżej na listingu:

   1: public class BaseClass
   2: {
   3:     public virtual void Execute()
   4:     {
   5:         Console.WriteLine("BaseClass.Execute");
   6:     }
   7: }
   8:  
   9: public class OverriderClass : BaseClass
  10: {
  11:     public override void Execute()
  12:     {
  13:         Console.WriteLine("OverriderClass.Execute");
  14:     }
  15: }

Wykonanie następującego kodu:

   1: OverriderClass overriderClass = new OverriderClass();
   2: BaseClass baseClass = overriderClass;
   3: overriderClass.Execute();
   4: baseClass.Execute();

Spowoduje wyświetlenie:

   1: OverriderClass.Execute
   2: OverriderClass.Execute

Czego myślę każdy się spodziewał. Wywołana została metoda, najbardziej pasującą do obiektu, na którego wskazują referencje.

Co natomiast stanie się, gdy usuniemy słowo kluczowe override? Wyświetli się coś takiego:

   1: OverriderClass.Execute
   2: BaseClass.Execute

Czyli nie mamy tutaj już do czynienia z polimorfizmem, tylko wywoływana jest metoda zależna od typu referencji, a nie obiektów, na który wskazuje referencja.

Co ciekawego możemy zobaczyć, to informacja jaką podczas kompilacji zwraca nam Visual Studio. Dokładnie treść ostrzeżenia: “OverriderClass.Execute() hides inherited member BaseClass.Execute(). To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.”

Visual Studio mówi nam w ostrzeżeniu, że jeśli chcemy skorzystać z polimorfizmu to powinniśmy użyć słowa kluczowego override. Natomiast jeśli świadomie chcemy nie korzystać z polimorfizmu i przykryć implementacje metody Execute, powinniśmy użyć słowa kluczowego new, aby dać kompilatorowi znać, że chcemy tak zrobić. Gdy nie podamy żadnego słowa kluczowego, kompilator zachowa się tak, jakbyśmy użyli słowa kluczowego new. Z tym wyjątkiem, że wygeneruje powyższy błąd.

Przy tym zagadnieniu wyraźnie widać jedną z różnic między c# a java. W javie wszystkie metody są domyślnie virtualne. W c# jest na odwrót.

Tags: , ,
Categories: Techniczne

Permalink E-mail | Kick it! | DZone it! | del.icio.us Komentarze (0) Post RSSRSS comment feed