kurs c#.doc

(211 KB) Pobierz
Ogólne

Ogólne

Język C# powstał specjalnie do programowania platformy .NET Framework. Jest on ściśle dopasowany do .NET CLR (Common Language Runtime) i odzwierciedla wiele jego cech, takich jak typy, zarządzanie pamięcią czy wyjątki. C# nie jest od razu kompilowany do postaci kodu maszynowego. Po kompilacji kodu źródłowego otrzymujemy IL (Intermediate Language) - dopiero podczas uruchamiania programu CLR przekształca IL do postaci wykonywalnej.

Program w C# jest tworzony poprzez budowanie nowych typów (głównie klas) oraz deklarowanie ich obiektów. W skład każdego typu wchodzą dane oraz funkcje składowe.

Dla kompilatora C# ułożenie oraz nazwy plików źródłowych - z rozszerzeniem .cs - nie mają znaczenia. Zgodnie z konwencją powinno się jednak każdą klasę umieszczać w osobnym pliku o nazwie odpowiadającej nazwie tej klasy, natomiast każdy plik powinien się znajdować w katalogu o nazwie odpowiadającej przestrzeni nazw, do której należy ta klasa.

C# nie posiada wbudowanych bibliotek. Zamiast tego korzysta z bibliotek BCL (Base Class Libraries) dostarczanych przez platformę .NET Framework (są one dostępne dla każdego języka .NET).


Najprostszy program w C#:

//  Plik źródłowy  Test.cs

class Test {

  static void Main( ) {

    System.Console.WriteLine( " Witaj !!! " ) ;

  }

}

Metoda Main jest domyślnym punktem wejścia do programu.

 

Operatory

 

Operatory uporządkowane względem priorytetu:

( )

grupowanie, np. (x+y) lub wywołania metody, np. f( )

.
->

operatory dostępu do składowych (klasy lub struktury).

[ ]

operator indeksowania (np. tablicy).

++
--

operatory post-inkrementacji i -dekrementacji. Operatory pre-inkrementacji i dekrementacji mają trochę niższe priorytety.

new

pozwala na wywołanie konstruktora i dynamiczne alokowanie nowego obiektu w pamięci. Zwraca referencję do utworzonego obiektu, np. MyClass a = new MyClass( ) ;

stackalloc

alokuje tablicę na stosie.

typeof

zwraca typ obiektu, np. System.Type t = typeof( MyClass );

sizeof

zwraca rozmiar struktury. Może być użyty jedynie w blokach unsafe. Np. int r = sizeof( int );

!
~

negacja logicza ( ! ) lub bitowa ( ~ ).

*

operator de-referencji (zwraca wartość zapisaną w miejscu o podanym adresie).

&

operator pobrania adresu (razem z operatorem * jest stosowany przy wskaźnikach).

( )

operator rzutowania typu, np. (typ) wartość

*
/
%

operatory mnożenia, dzielenia oraz reszty z dzielenia (%).

+
-

operatory dodawania i odejmowania.

>>
<<

przesunięcie bitowe w prawo lub w lewo.

>
<
>=
<=

operatory relacji (większości, mniejszości, ... , mniejsze lub równe).

is

operator zgodności typów. Np. if( x is int) { ... }

as

: pozwala rzutować w dół hierarchii klas. Przy niepowodzeniu zwraca null.

==
!=

operatory równości i nierówności

|
&
^

operatory logiczne bitowe.

||
&&

operatory logicznej alternatywy ( || ) oraz koniunkcji ( && ).

?:

trójargumentowy operator warunku. ( warunek ? a : b ) zwróci a gdy warunek ma wartość true lub b gdy warunek ma wartość false.

=
*=

operatory przypisania. Działanie (a *= b) jest równoważne ( a = a * b ). Podobnie działają inne operatory przypisania: /= += -= %= &= ...

 

Gdy operatory mają ten sam priorytet (np. + oraz - ) o ich kolejności decyduje łączność. Operatory przypisań oraz jednoargumentowe łączą od prawej strony, natomiast operatory dwuargumentowe (z wyjątkiem przypisań) łączą od lewej, np.
a = b = c jest równoważne: a = (b = c)
a + b + c jest równoważne: (a + b) + c

Ponadto istnieją operatory checked i unchecked służące do sprawdzania przepełnienia, np. int a = checked( b * c ) ; gdzie b oraz c są typu int

Operator checked oblicza wyrażenie podczas działania programu i jeśli jego wartość wychodzi poza dopuszczalny zbiór wartości zwraca wyjątek OverflowException (domyślnie poprawność jest sprawdzana tylko w momencie kompilacji). Operatora checked można używać także w stosunku do całego bloku instrukcji, np. checked { ... ; a = b * c ; ... } . Operator unchecked wyłącza natomiast sprawdzanie wyrażeń arytmetycznych podczas kompilacji (przydaje się bardzo rzadko)

Deklaracje

Każda deklarowana zmienna lub funkcja jest składową jakiegoś typu (klasy, struktury). Bezpośrednio w przestrzeni nazw możemy deklarować tylko typy. Kolejność deklaracji nie ma znaczenia.

Każdy identyfikator jest słowem złożonym ze znaków Unicode, zaczynającym się od litery lub znaku podkreślenia. Brana jest pod uwagę wielkość liter. Zasięg identyfikatora rozciąga się do końca bieżącego bloku programu.

 

Rodzaje typów:

W C# wszystkie typy (predefiniowane oraz stworzone przez programistę) należą do jednej z trzech kategorii :

Bezpośrednie : (value type) są strukturami przechowywanymi (na stosie) jako wartości. Do tej kategorii należą takie typy jak np. int, bool, float, char ... oraz struktury. Jeśli typ bezpośredni jest składową większego obiektu (klasy, tablicy), to jest przechowywany bezpośrednio jako część tego obiektu.

Referencyjne : (reference type) ich wartości są przechowywane na stercie (w pamięci rezerwowanej dynamicznie), na stosie znajdują się jedynie referencje (wskazania) do obiektów. Do tej kategorii należą wszystkie klasy (np. object, string), ale także tablice czy interfejsy. Zmienna typu referencyjnego może mieć wartość null oznaczającą, że nie wskazuje żadnego obiektu. Obiekt typu referencyjnego pozostaje na stercie tak długo, aż system nie stwierdzi, że nie ma już żadnych odwołań do tego obiektu (W C# mamy do czynienia z automatycznym zwalnianiem pamięci zajmowanej przez nieużywane obiekty).

Wskaźnikowe : używane do jawnego manipulowania pamięcią. Zwykle się ich nie używa (ponadto wskaźniki mogą być używane tylko w blokach nienadzorowanych).

Przypisanie (operator = ) typu referencyjnego polega na skopiowaniu wskazania na obiekt (nie powstaje nowy egzemplarz obiektu, a tylko mamy kolejne wskazanie na ten sam obiekt). Przypisanie (i ogólnie odwołanie się) typu bezpośredniego polega na skopiowaniu wartości całego obiektu.

Każdy typ bezpośredni posiada (niejawny) przypisany do niego typ referencyjny. W momencie rzutowania typu bezpośredniego na typ referencyjny automatycznie jest tworzony obiekt tego typu referencyjnego. Dzięki temu typy bezpośrednie możemy traktować jako pochodne typu object.

void : typ pusty. Możemy deklarować metody (ew. delegacje) tego typu - w takim wypadku metoda nie musi zwracać żadnej wartości.

null : słowo kluczowe oznaczające pustą referencję (wskazanie puste). Zmienna typu referencyjnego mająca wartość null nie wskazuje na żaden obiekt.

 

Rodzaje dostępu:

W C# zdefiniowano pięć rodzajów dostępu do typów i ich składowych:

public : składowa lub typ zadeklarowany jako publiczny są dostępne z dowolnego miejsca. Ten rodzaj dostępu jest domyślny dla interfejsów.

private : składowa zadeklarowana jako prywatna jest dostępna tylko z wnętrza typu, w którym została zadeklarowana. Ten rodzaj dostępu jest domyślny dla składowych klas i struktur.

protected : składowa zadeklarowana jako chroniona jest dostępna z wnętrza klasy, w której została zadeklarowana lub z wnętrza klasy pochodnej.

internal : typ lub składowa typu są dostępne tylko z wnętrza złożenia, w którym nastąpiła ich deklaracja (podczas kompilacji pliki .cs z kodem źródłowym programu są kompilowane w moduły - zgodnie z podziałem na przestrzenie nazw - a następnie grupowane w złożenia, ang. assembly)

protected internal : składowa zadeklarowana z takim rodzajem dostępu jest widoczna z wnętrza klasy, w której została zadeklarowana (lub klasy pochodnej od niej) oraz z wnętrza złożenia, w którym się znajduje.

Wymienione rodzaje dostępu można stosować w stosunku do typów (klas, struktur) oraz ich składowych (metod i danych). Każdy typ/składowa w C# posiada któryś z wymienionych rodzajów dostępu (co najwyżej przypisany domyślnie).

 

Typy predefiniowane w C#:

int : ( inaczej System.Int32). Liczba całkowita ze znakiem, zajmująca 4 bajty.

uint : ( System.UInt32). Liczba całkowita bez znaku. Zajmuje 4 bajty.

short : ( System.Int16 ). Liczba całkowita krótka ze znakiem. Zajmuje 2 bajty.

ushort : ( System.UInt16). Liczba całkowita krótka bez znaku. Zajmuje 2 bajty.

long : ( System.Int64 ). Liczba całkowita długa ze znakiem. Zajmuje 8 bajtów.

ulong : ( System.UInt64 ). Liczba całkowita długa bez znaku. Zajmuje 8 bajtów.

byte : ( System.Byte ). Pojedynczy bajt, bez uwzględnienia znaku. Istnieje także typ sbyte (System.Sbyte ) oznaczający pojedynczy bajt (ew. małą liczbę całkowitą) ze znakiem.

char : ( System.Char ) reprezentuje pojedynczy znak Unicode. Zajmuje 2 bajty. Literał tego typu zapisujemy w apostrofach, np. 'A' (znak A) lub '\u0041' (zapis w Unicode). Ponadto możemy używać pewnych sekwencji specjalnych, np. '\n'' (znak nowej lini), '\t' (tabulacja), ' \" ' (cudzysłów), '\'' (apostrof), '\0' (null).

bool : ( System.Boolean ) typ logiczny mogący przyjmować wartośći true lub false . Nie można dokonywać konwersji z bool na typ całkowity lub odwrotnie.

float : ( System.Single ) liczba zmiennopozycyjna pojedynczej precyzji. Zajmuje 4 bajty. W zakresie wartości typów zmiennopozycyjnych (float i double) mieszczą się wartości specjalne ?0, ?? oraz NaN (not a number). Literały typu float zapisujemy z przyrostkiem 'f' lub 'F', np. 9.4f Domyślnie literał zmiennopozycyjny jest typu double (co można dodatkowo podkreślić używając przyrostków 'd' lub 'D').

double : ( System.Double ) liczba zmiennopozycyjna podwójnej precyzji. Zajmuje 8 bajtów.

decimal : ( System.Decimal ) liczba w systemie dziesiętnym zajmująca 12 bajtów (przechowuje 28 cyfr oraz pozycję punktu dziesiętnego w tych liczbach). Ma mniejszy zakres w porównaniu z liczbami zmiennopozycyjnymi jednak zapewnia bardzo dużą precyzję przechowywania liczb o podstawie 10. Liczba zapisywana jako dziesiętna wymaga przyrostka 'm' lub 'M', np. decimal d = 10.1m ;

object : ( System.Object ) typ bazowy dla wszystkich innych typów (z wyjątkiem wskaźnikowych). Powoduje narzut 8 bajtów pamięci dla egzemplarzy typów wywodzących się z niego przechowywanych na stercie (w wypadku przechowywania na stosie nie ma narzutu).

string : ( System.String ) reprezentuje łańcuch (zmiennej długości) znaków Unicode. Możemy używać tych samych sekwencji specjalnych co w przypadku typu char, np. '\n', '\0', ... Pomimo tego, że string jest klasą (typem referencyjnym) ma pewne szczególne przywileje - można go tworzyć bez użycia operatora new, np. string s = " tekst \n " ; Poza zwykłymi literałami łańcuchowymi istnieją także tzw. literały dosłowne - zawarte wewnątrz @"...". Zawartość wewnątrz takiego literału jest brana 'dosłownie'. Tożsame są łańcuchy @"\\serwer\plik.txt" oraz "\\\\serwer\\plik.txt" .

Zapisując literał oznaczający liczbę możemy określić typ literału itp. , np.
0x5 : liczba 5 w systemie szesnastkowym. Literały szesnastkowe mają przedrostek 0x
5UL : oznacza wartość 5 typu ulong ( U - liczba bez znaku, L - liczba długa ).

 

Zmienne:

Zmienna (dostępna poprzez identyfikator) reprezentuje miejsce w pamięci. Każda zmienna posiada swój typ, który określa zbiór możliwych wartości i operacji. C# jest językiem o ścisłej typizacji, zbiór możliwych operacji dostępnych dla danego typu/zmiennej jest określany już podczas kompilacji, a zmienna jest dostępna tylko poprzez powiązany z nią typ. Zmienne deklarujemy według wzoru: modyfikatory typ identyfikator = wartPocz; (Modyfikatory oraz wartość początkowa nie są wymagane)
Np. int a = 10 ;


Dostępne modyfikatory:

static : pozwala zadeklarować składową statyczną (istniejącą na rzecz całego typu, a nie pojedynczego obiektu tego typu). Składowe statyczne nie wymagają istnienia obiektów. Dana składowa statyczna istnieje jeszcze przed pojawieniem się pierwszego obiektu danej klasy - ponadto istnieje tylko jedna jej wartość, wspólna dla wszystkich obiektów klasy,
np. ...

Zgłoś jeśli naruszono regulamin