Podstawy C#
-
Upload
truonghanh -
Category
Documents
-
view
218 -
download
0
Transcript of Podstawy C#
Nowa wersja C#
Autor: Piotr Sobczak
Seminarium magisterskie „Zagadnienia programowania obiektowego”Wydział Matematyki, Informatyki i MechanikiUniwersytet Warszawski
PLAN- podstawy: Wprowadzenie Przestrzenie nazw Typy, parametry, konwersje Klasy Instrukcje sterujące Właściwości Interfejsy, operatory is i as Wyjątki Delegaty
PLAN – rozszerzenia w C# 2.0:
Typ generyczny Metody anonimowe Typ dzielony Typ „nullable” Podsumowanie i wnioski
Wprowadzenie
Język zorientowany-obiektowo, powstały na bazie C++ i Java
Pierwszy język programowania komponentowego z rodziny C/C++
Obsługuje: klasy, interfejsy, struktury Główny architekt – Anders Hejlsberg
Klasy Definicja klasy jest połączona z deklaracją –
nie ma osobnych plików .h/.cpp, jak w przypadku C++
Przykład:public class HelloWorld
{
public static void Main()
{
System.Console.WriteLine(”Witamy w .NET”);
}
}
Klasy – modyfikatory dostępu
Modyfikatory występują przed deklaracjami klas, metod, atrybutów.
public brak ograniczeń private dostęp tylko z wewnątrz klasy protected dostęp z wewnątrz klasy oraz z klas
dziedziczących internal dostęp z klas z tego samego pakietu protected internal = protected OR internal
Klasy z atrybutem sealed
Jeżeli deklaracja klasy zawiera atrybut sealed, to nie jest możliwe jej dziedziczenie
sealed public class MojaKlasa{}
Tworzenie obiektów
Tak samo jak w C++
Button b = new Button();
Klasa object Wszystkie klasy dziedziczą po object
Zamiana na object może być niejawna, lecz w drugą stronę wymagane jest jawne rzutowanie
int i = 10;object obj = i;
int j = (int) obj;
Konwersje między typami
niejawne (dopuszczalne, gdy nie ma straty)short x = 5;int y = x; // int ma 32bity, a short 16, wiec ok.
jawne (wymagane przy możliwości straty)int x = 500;short y = (short) x; // bez wymuszenia się nie skompiluje
Przestrzenie nazw (namespaces)
Zapobiegają występowaniu konfliktów w nazwach klas
Grupują klasy o podobnym zastosowaniu Separatorem jest ‘.’ (znak kropki)
System.Console.WriteLine(”Tralalala”);System.Windows.Forms.Button b = new
System.Windows.Forms.Button();
namespace - deklarowanienamespace Nazwa{
namespace NazwaWewnetrzna{
class PrzykladowaKlasa{
…}
}}
Odwołanie z zewnątrz:Nazwa.NazwaWewnetrzna.PrzykladowaKlasa
Słowo kluczowe using
using System;
…
Console.WriteLine(”Witamy w .NET”);
using System.Console;
…
WriteLine(”Witamy .NET”);
UWAGA! Po UWAGA! Po using using nie podajemy nazwy klasy, tylko namespacenie podajemy nazwy klasy, tylko namespace
System typów
Wspólny system typów (Common Type System)
Typy użytkownikaTyp wyliczeniowyStruktury
Typy proste i typy referencyjne Typy proste
Pamiętają bezpośrednio dane
Każdy zawiera oddzielną kopię danych
Operacje na jednej zmiennej nie mają wpływu na inne
Typy referencyjne
Pamiętają referencję na pamiętane dane
Dwie zmienne mogą wskazywać na tą samą daną
Operacje na jednej zmiennej mogą mieć wpływ na inne
Typy proste wbudowane
8-bitowe: byte, char, sbyte16-bitowe: short, ushort32-bitowe: int, uint, float64-bitowe:double, decimal, long, ulong
int liczba == System.Int32 liczbalong liczba == System.Int64 liczba
Tworzenie typów użytkownika
Typ wyliczeniowydefiniowanie enum Kolor{Czerwony,Zielony,Niebieski};
sposób użyciaKolor kolor1 = Kolor.Czerwony;
Tworzenie typów użytkownika cd.. Struktury
definiowanie struct Osoba
{ public string Imie, Nazwisko; public int Wiek; }sposób użycia Osoba pracownik;
pracownik.Imie = "Jan";pracownik.Wiek = 30;
Przekazywanie parametrów 1/2
Przez wartość przekazywane są przedstawione typy wbudowane oraz:
enum, struct
Pozostałe typy przekazywane są przez referencję.
Przekazywanie parametrów (2/2)
Typ podstawowy można przekazywać przez referencję wykorzystując słówko pomocnicze ref
public void Inkrementuj(ref int liczba){
liczba++;}
W wywołaniu metody także używamy ref:Inkrementuj(ref liczba);
DziedziczeniePrzykład: class rodzic { virtual public void dajkasę() {...} } class dziecko: rodzic { override public void dajkasę() {...} } NIE jest dopuszczalne dziedziczenie wielokrotne Rozwiązanie poprzez implementację
Interfejsów
if…else
Identyczna składnia, jak w C++ / Java
Warunek musi być typu bool (nie może być int, jak w C++)
Unikamy więc błędów typu:if (zmienna = 5)
switch (1/2)
Nie jest dopuszczalny automatyczny przeskok do kolejnego przypadku
case 0:ZrobCos();break;
case 1:
poza sytuacją, gdy case jest „pusty”case 0:case 1:
ZrobCos();
Bez tego program się nie skompiluje
switch (2/2) Skok do innego przypadku musi być jawny
case 0:ZrobCos();goto case 1;
case 1:
Wyrażenie może być string-iem (w C++ wymagany był int)
switch (nazwisko){
case „Kowalski”:ZrobCos();break;
case „Nowak”:ZrobCosInnego();break;
}
while, do…while
while (i < 10){
Console.WriteLine(„Wartość {0}”, i);}
do{
Console.WriteLine(„Wartość {0}”, i);} while (i < 10);
for – zakres zmiennych
Zmienne zadeklarowane w pętli for obowiązują jedynie wewnątrz pętli (tak jak w Javie; w C++ zależało to od wersji języka)
for (int i = 0; i < 10; i++){
…}for (int i = 5; i < 20; i++){
…}
Foreachforeach (string nazwa in wszystkieNazwy)
{
Console.WriteLine(nazwa);
}
Wymagane: wszystkieNazwy musi realizować interfejs IEnumerable
Tablice a „params” Pozwala tworzyć metody z nieokreśloną liczbą argumentów
public int Sumuj(params int[] skladniki){
int suma = 0;foreach (int skladnik in skladniki){
suma += skladnik;}return suma;
}
Sumuj (1, 2, 3, 4); == 10Sumuj (5, 6); == 11Sumuj (); == 0
Właściwości/własności Class Test Użycie:{ Test pom=new
Test(); private int liczba; int x =pom.Liczba; public int Liczba pom.Liczba=1; {
get{return liczba;}set{liczba = value;if (liczba < 0) liczba = 0;}
}}
Implementacja interfejsówinterface ITestable{
bool TestMe();}
public class MojaKlasa : ITestable{
bool TestMe(){
…}
}
Operator IS is is służy do sprawdzenia, czy obiekt można rzutować na wybrany służy do sprawdzenia, czy obiekt można rzutować na wybrany
typ bez rzucania wyjątkówtyp bez rzucania wyjątków
objectobject obiekt = obiekt = newnew MojaKlasa(); MojaKlasa();
ifif (obiekt (obiekt isis MojaKlasa) MojaKlasa){{
((MojaKlasa)obiekt).Zagraj();((MojaKlasa)obiekt).Zagraj();}}
Możemy też sprawdzać, czy obiekt implementuje wybrany interfejs:Możemy też sprawdzać, czy obiekt implementuje wybrany interfejs:
ifif (obiekt (obiekt isis ITestable) ITestable)
Operator as Łączy is z operatorem rzutowania. Jeśli rzutowanie
nie jest możliwe, zwraca null
protected void clicked(object sender, EventArgs e){
Button b = sender as Button;if (b != null){b.Text = „Naciśnięto”;}
}
Kolekcje
ArrayList tablica Queue kolejka Stack stos Dictionarystruktura słownikowa
(łączy klucz-wartość) Hashtable tablica haszująca
Wyjątki (1/3)try{
…}catch (IOException exception){
…}catch (Exception exception){
…}finally{
…}
Wyjątki (2/3) Dopuszczalne jest użycie samego catchtry{
…}catch {
…} throw: słowo kluczowe umożliwiające zgłoszenie
wyjątku
Wyjątki (3/3) Wymagana jest odpowiednia kolejność catchtry{
…}catch (Exception exception){
…}catch (IOException ioexception){
// tutaj nigdy nie dojdziemy, bo IOException jest // specjalizacją Exception, więc poprzedni catch // wyłapie ewentualny wyjątek
}
Odpowiedniki wskaźników do funkcji z C++Odpowiedniki wskaźników do funkcji z C++
publicpublic delegatedelegate intint KtoryMniejszy ( KtoryMniejszy (objectobject o1, o1, objectobject o2); o2);
KtoryMniejszyKtoryMniejszy Porownanie Porownanie +=+= newnew KtoryMniejszy KtoryMniejszy (FunkcjaPorownawcza);(FunkcjaPorownawcza);
publicpublic intint FunkcjaPorownawcza ( FunkcjaPorownawcza (objectobject o1, o1, objectobject o2) o2){{
returnreturn (o1>o2); (o1>o2);}}
Tab.sort(Porownanie);Tab.sort(Porownanie);
Delegaty
Delegaty i zdarzenia Delegaty są wykorzystywane do obsługi
zdarzeń
delegate void EventHandler (object sender, EventArgs e);
button1.Click += new EventHandler (KliknietoNaPrzycisku);
void KliknietoNaPrzycisku (object sender, EventArgs e){
Button nadawca = sender as Button;…
}
GENERICS
Generics pozwala klasom, strukturom, interfejsom, delegatom i metodom być sparametryzowanym przez typ który przechowują i manipulują nim.
Jest podobny do generics w jezyku Eiffel ,Ada lub szablonów w C++.
Dlaczego GENERICS?
public class Stack{object[] items;int count; public void Push(object item) {...} public object Pop() {...}}
Stack stack = new Stack(); stack.Push(new Customer()); Customer c = (Customer)stack.Pop();
Generics
public class Stack<T> {
T[] items; int count;
public void Push(T item) {...} public T Pop() {...} }
Stack<int> stack = new Stack<int>();stack.Push(3);int x = stack.Pop();
Generics- liczba paramerówpublic class Dictionary<K,V>
{public void Add(K key, V value) {...}
public V this[K key] {...}}
Dictionary<string,Customer> dict new Dictionary<string,Customer>();
dict.Add("Peter", new Customer()); Customer c = dict["Peter"];
Generics - aliasy
using List = LinkedList<int,string>;
class ListClient{ static void Main(string[]args) { List list = new List(); list.AddHead(123,"AAA"); } }
Generics - kompilacja
Kompiluje się do IL (instrukcje i metadane) Proces tworzenia – generic type instantion Po jednej instancji dla każdego typu
prostego Jedna instancja dla typów referencyjnych
Generics – nie tylko dane 1/2 Nie tylko przechowywanie danych typu generycznego
public class Dictionary<K,V>{ public void Add(K key, V value) {
... if (key.CompareTo(x) < 0) {...} // Error, no ... }}
Generics – nie tylko dane 2/2 Rozwiązanie za pomocą rzutowania:
public class Dictionary<K,V>{public void Add(K key, V value){... if (((IComparable)key).CompareTo(x) <0) {...}...}}
Generics – Constraints 1/2 Czyli ograniczenia na parametry:
public class Dictionary<K,V> where K: IComparable{public void Add(K key, V value){...
if (key.CompareTo(x) < 0) {...}...}}
Generics – Constraints 2/2 Ograniczenia mogą dotyczyć wielu Interfejsów,
1 klasy, a także konstruktora new().
public class EntityTable<K,E> where K: IComparable<K>, IPersistable
where E: Entity, new(){
public void Add(K key, E entity){
... if (key.CompareTo(x) < 0) {...}
...}
}
Metody Generyczne 1/2
Możemy sparametryzować także metody.void PushMultiple<T> (Stack<T> stack, params T[] values) {
foreach (T value in values) stack.Push(value);}
Stack<int> stack = new Stack<int>();PushMultiple<int>(stack, 1, 2, 3, 4);
Metody Generyczne 2/2 type inferencing – wywołanie metody z odpowiednim
typem generycznym na podstawie parametrów. Stack<int> stack = new Stack<int>();
PushMultiple(stack, 1, 2, 3, 4);
tak jak dla klas możemy wprowadzać też ograniczenia dla metod:
public class MyClass{ public void SomeMethod<T>(T t)
where T :IComparable<T> {...}}
Typ generyczny i rzutowanie 1/3 Niejawnie możemy rzutować do object i do
typów występujących w ograniczeniach: class MyClass<T> where T : BaseClass,ISomeInterface { void SomeMethod(T t) { ISomeInterface obj1 = t; BaseClass obj2 = t; object obj3 = t; }
}
Typ generyczny i rzutowanie 2/3 Jawnie rzutować możemy tylko do
interfejsów:
class MyClass<T> { void SomeMethod(T t) { ISomeInterface obj1 = (ISomeInterface)t; //Compiles
SomeClass obj2 = (SomeClass)t; //Does not compile }
}
Typ generyczny i rzutowanie 3/3 Możemy ominąć to ograniczenie używając
zmiennej pomocniczej typu object: class MyClass<T> { void SomeMethod(T t) { object temp = t; SomeClass obj = (SomeClass)temp; } }
Warto używać operatorów is i as.
Dziedziczenie i generics 1/2 Jeżeli klasa dziedziczy z klasy generycznej to musi być
podany konkretny typ jako parametr:
public class BaseClass<T>{...} public class SubClass : BaseClass<int>{...}
Chyba że klasa i podklasa są sparametryzowane tym samym parametrem:
public class SubClass<T> : BaseClass<T> {...}
Dziedziczenie i generics 2/2 Przy dziedziczeniu należy powtarzać
ograniczenia w podklasach:public class BaseClass<T> where T : ISomeInterface {...}public class SubClass<T> : BaseClass<T> where T : ISomeInterface{...}
To samo dotyczy metod wirtualnych:public class BaseClass{
public virtual void SomeMethod<T>(T t) where T : new() {...}}public class SubClass : BaseClass{
public override void SomeMethod<T>(T t) where T : new() {...}
}
Generics i delegaty Tak jak klasy struktury i interfejsy
możemy sparametryzować typem generycznym także delegaty:
public delegate void GenericDelegate<T>(T t); public class MyClass{ public void SomeMethod(int number) {...}}MyClass obj = new MyClass();GenericDelegate<int> del; del = new GenericDelegate<int>(obj.SomeMethod);
del(3);
Kolekcje Generyczne
System.Collections.Generics i odpowiedniki System.Collections
Comparer<T> ComparerDictionary<K,T> HashTableList<T> ArrayListQueue<T> QueueSortedDictionary<K,T> SortedListStack<T> StackIComparable<T> IComparable
Metody anonimowe 1/3 Zdarzenia są obsługiwane przez metody na które
wskazują delegaty. class InputForm: Form
{ListBox listBox;TextBox textBox;Button addButton;
public MyForm() {listBox = new ListBox(...);textBox = new TextBox(...);addButton = new Button(...);
addButton.Click += new EventHandler(AddClick);
} void AddClick(object sender, EventArgs e) {
listBox.Items.Add(textBox.Text);}
}
Metody anonimowe 2/3 Ten sam przykład z użyciem metody anonimowej: class InputForm: Form
{ListBox listBox;TextBox textBox;Button addButton;
public MyForm() {listBox = new ListBox(...);textBox = new TextBox(...);addButton = new Button(...);
addButton.Click += delegate {listBox.Items.Add(textBox.Text);
}; }
}
Metody anonimowe 3/3 Możemy także używać metod anonimowych do
wpisywania funkcji “in-line” delegate double Function (double x);class Test
{static double[] Apply(double[] a, Function f) { … }
static double[] MultiplyAllBy(double[] a, double factor) {
return Apply(a, delegate(double x) { return x * factor; });
} static void Main() {
double[] a = {0.0, 0.5, 1.0}; double[] squares = Apply(a, delegate(double x) { return x * x; });
double[] doubles = MultiplyAllBy(a, 2.0);}
}
Iteratory 1/3
Żeby można było użyć pętli foreach na kolekcji, to kolekcja musi spełniać warunki:
Kolekcja musi implementować interfejs IEnumrable.
Kolekcja musi mieć bezparametrową metodę GetEnumerator.
Iteratory 2/3 „Numeratory” są trudne do zaimplementowania. Sprawę ułatwiają nam ITERATORY: public class Stack<T>: IEnumerable<T>
{T[] items;int count;
public void Push(T data) {...} public T Pop() {...} public IEnumerator<T> GetEnumerator()
{for (int i = count – 1; i >= 0; --i) {
yield return items[i];}
}}
Mamy też do dyspozycji instrukcję yield break
Iteratory 3/3 Możemy także zdefiniować kilka iteratorów dla 1
kolekcji:public class Stack<T>: IEnumerable<T>
{…
public IEnumerator<T> GetEnumerator() {for (int i = count – 1; i >= 0; --i) {yield return items[i];}} public IEnumerable<T> TopToBottom {get {return this; }}
public IEnumerable<T> BottomToTop {get {for (int i = 0; i < count; i++) {yield return items[i];} }}}
Iteratory 3/3 cd..Użycie: class Test
{static void Main()
{ Stack<int> stack = new Stack<int>(); for (int i = 0; i < 10; i++) stack.Push(i);
foreach (int i in stack.TopToBottom) Console.Write("{0} ", i);
foreach (int i in stack.BottomToTop) Console.Write("{0} ", i);
}}
Partial types 1/2 Podział zawartości 1 klasy w więcej niż jednym pliku np:
plik1.cs public partial class Customer
{private int id;private string name;private string address;private List<Order> orders;
public Customer() {...
} }
Partial types 2/2 Plik2.cs public partial class Customer
{public void SubmitOrder(Order order) {
orders.Add(order);}
public bool HasOutstandingOrders() {return orders.Count > 0;
}}
Nullable type 1/3
Wprowadza dla wszystkich typów prostych wartość null.
int? Jest to typ wbudowany + wartość null. HasValue - właściwość, która zwraca nam
true or false jeżeli typ jest nullable lub nie.
Nullable type 2/3
Operacje arytmetyczne z null-em dają null Operatory >,<,<=, >= zwracają false jeżeli
któryś z argumentów jest null. Nowy operator ??. a??b – rezultatem jest a jeżeli a jest
not-null i b w przeciwnym przypadku.
Nullable type 3/3 Przykład: int? x = GetNullableInt();
int? y = GetNullableInt();int? z = x ?? y;int i = z ?? -1;
Operator ten działa też dla typów referencyjnych:
string s = GetStringValue();Console.WriteLine(s ?? "Unspecified");
PODSUMOWANIE
Została zachowana maksymalna zgodność wstecz.
Jeszcze większy wachlarz konstrukcji. Ciągle najlepszy język do programowania
na platformie .NET
Koniec.Dziękuję za uwagę.