166
C#, Visual Studio C#, Visual Studio 2010, 2010, .NET 4.0 .NET 4.0 dr inż. Marcin Radom Instytut Informatyki, Politechnika Poznańska laboratorium Programowania Wizualnego 1

C#, Visual Studio 2010, .NET 4.0

  • Upload
    tino

  • View
    39

  • Download
    4

Embed Size (px)

DESCRIPTION

C#, Visual Studio 2010, .NET 4.0. dr inż. Marcin Radom Instytut Informatyki, Politechnika Poznańska laboratorium Programowania Wizualnego. Część I: Wstęp, C# i .NET. Tajemnicze skróty z .NET. CLR – Common Language Runtime CTS – Common Type System CLS – Common Language Specification - PowerPoint PPT Presentation

Citation preview

Page 1: C#, Visual Studio 2010, .NET 4.0

C#, Visual Studio 2010,C#, Visual Studio 2010,.NET 4.0.NET 4.0

dr inż. Marcin RadomInstytut Informatyki, Politechnika

Poznańskalaboratorium Programowania Wizualnego

1

Page 2: C#, Visual Studio 2010, .NET 4.0

Część I:Część I:Wstęp, C# i .NETWstęp, C# i .NET

2

Page 3: C#, Visual Studio 2010, .NET 4.0

CLR – Common Language RuntimeCTS – Common Type SystemCLS – Common Language SpecificationJIT(ter) – Just-in-time CompilerCIL – Common Intermediate Language

(przez JIT).NET Metadata.NET Asembly Manifest

3

Tajemnicze skróty z .NETTajemnicze skróty z .NET

Page 4: C#, Visual Studio 2010, .NET 4.0

ildasm.exe ( \Program Files\Microsoft SDKs\7.0A\bin\ )

Reflector ( http://www.red-gate.com/products/reflector )

4

Użyteczne programyUżyteczne programy

Page 5: C#, Visual Studio 2010, .NET 4.0

5

Część II:Część II:Programowanie w C#Programowanie w C#

Page 6: C#, Visual Studio 2010, .NET 4.0

csc.exe ( dostęp np. poprzez link w zainstalowanym folderze menu Start )

Parametry:/out/target:exe (library, module, winexe)

C:\csc.exe /target:exe Program.csC:\csc *.csC:\csc /out:MojProgram.exe @Program.rsp

6

Kompilator konsolowyKompilator konsolowy

Page 7: C#, Visual Studio 2010, .NET 4.0

Pliki *.rscPliki *.rsc # External assembly references.

/r:System.Windows.Forms.dll# Output and files to compile (using wildcard syntax)./target:exe /out:Program.exe *.cs

csc.rsp ( \Windows\Microsoft.NET\Framework\<version> )

7

Page 8: C#, Visual Studio 2010, .NET 4.0

Inne programyInne programyNotepad++

http://notepad-plus.sourceforge.net

SharpDevelophttp://www.sharpdevelop.com

Monohttp://www.mono-project.com

Visual C#2010 Express

8

Page 9: C#, Visual Studio 2010, .NET 4.0

Cechy MS Visual Studio Cechy MS Visual Studio 20102010Solution Explorer UtilityReferencing External AssembliesProject PropertiesClass View UtilityObject Browser UtilityIntegrated Support for Code

RefactoringCode Expansion and Surround With

TechnologyVisual Class Designer

9

Page 10: C#, Visual Studio 2010, .NET 4.0

Część III:Część III:Podstawy (1)Podstawy (1)

10

Page 11: C#, Visual Studio 2010, .NET 4.0

Hello World w C#Hello World w C#

using System;using System.Collections.Generic;using System.Linq;using System.Text;

namespace ConsoleApplicationExemplar{ class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.WriteLine(); Console.ReadLine(); } }}

11

Page 12: C#, Visual Studio 2010, .NET 4.0

Przetwarzanie parametrów Przetwarzanie parametrów wejściowychwejściowych

for(int i = 0; i < args.Length; i++)Console.WriteLine("Arg: {0}", args[i]);

-wyświetli listę parametrów startowych

foreach(string arg in args)Console.WriteLine("Arg: {0}", arg);

-jak wyżej

string[] theArgs = Environment.GetCommandLineArgs();foreach(string arg in theArgs)

Console.WriteLine("Arg: {0}", arg);

-jak wyżej12

Page 13: C#, Visual Studio 2010, .NET 4.0

Obiekty Environment, Console – i ich Obiekty Environment, Console – i ich przydatne metody (do sprawdzenia we przydatne metody (do sprawdzenia we własnym zakresie)własnym zakresie)

Environment.OSVersion (ProcessorCount, Version)

Console.WriteLine (ReadLine, Beep(), BackgroundColor, BufferHeight, Width, Title, Clear, etc. )

Console.WriteLine( „{0} oraz {0}”, 9 );

{0:c} {0:d9} {0:f3} etc…

13

Page 14: C#, Visual Studio 2010, .NET 4.0

ZmienneZmiennefloat L1 = 7.4F; (bez F – double)

long L2 = 10D; (bez D – int)

ponieważ liczby w C# to struktury, można wykonać operacje:◦12.GetHashCode(); //12◦12.Equals(23); //FALSE◦12.ToString(); //12

◦double.MaxValue◦double.PositiveInfinity, etc…

14

Page 15: C#, Visual Studio 2010, .NET 4.0

BigInteger – na naprawdę BigInteger – na naprawdę duże liczbyduże liczby System.Numerics (References->Add reference

->zakładka .NET )

static void UseBigInteger(){ Console.WriteLine("Use BigInteger:"); BigInteger dlug =

BigInteger.Parse(„10000000000000000000000000000000999");

Console.WriteLine("{0}", dlug); Console.WriteLine("{0}", dlug.IsEven); Console.WriteLine("{0}", dlug.IsPowerOfTwo); BigInteger dlugUSA = BigInteger.Multiply(dlug, BigInteger.Parse("100000000000000000000000000000000"); Console.WriteLine("{0}", dlugUSA);}

15

Page 16: C#, Visual Studio 2010, .NET 4.0

ŁańcuchyŁańcuchy

String – czyli to co wszyscy znają

Łańcuchy dosłowne (verbatim) @ - wszystko wewnątrz jest traktowane jako łańcuch, nawet (a raczej: zwłaszcza) wszystkie znaki specjalne jak / \ ” itd.

StringBuilder (System.Text) - jeżeli chcemy oszczędzać pamięć

16

Page 17: C#, Visual Studio 2010, .NET 4.0

Rozszerzanie / zawężanie Rozszerzanie / zawężanie typów danychtypów danych

implicit / explicit – sposób przypisywania zmiennych różnych typów – pierwszy to domyślny, nie działa przy przekraczaniu zakresu typu, drugi wprost mówi kompilatorowi, że wiemy co robimy, np. zmienna_int = (int)wielki_float;

checked / unchecked

Opcje domyślne dla środowiska w kwestiach powyższych: Properties -> Build -> [Advanced]Button

17

Page 18: C#, Visual Studio 2010, .NET 4.0

Zmienna typu zmienna, czyli Zmienna typu zmienna, czyli typ ’var’typ ’var’ var cos = 0; cos.GetType().Name //wynik: int

var myInt = 0;var myBool = true;var myString = "Time, marches on...";

Błędy:◦ public var cos = 0;◦ public var Metoda(var x);◦ var cos; cos=0;◦ var obiekt = null;

◦ var? nic = nowyObiekt();◦ var? blad = 12;

18

Page 19: C#, Visual Studio 2010, .NET 4.0

(Elementarne) konstrukcje (Elementarne) konstrukcje językajęzykaPętle:foreach ; forwhile ; do / while

Instrukcje warunkowe:if / else

switch () {

case 1:….break;

case 2:….break

default:….break

}

19

Page 20: C#, Visual Studio 2010, .NET 4.0

Część IV:Część IV:Podstaw ciąg dalszyPodstaw ciąg dalszy

20

Page 21: C#, Visual Studio 2010, .NET 4.0

Parametry argumentów Parametry argumentów metod: out, ref, paramsmetod: out, ref, params

OUT – wywoływana metoda MUSI zwrócić wartość REF – wywoływana metoda może trwale zmienić wartość PARAMS – w skrócie(wielkim): nieokreślona liczba zmiennych

pewnego typu

public static void SwapStrings(ref string s1, ref string s2) { string tempStr = s1; s1 = s2; s2 = tempStr; }

static void Main(string[] args) { Console.WriteLine("**********"); string s1 = "Flip"; string s2 = "Flop"; Console.WriteLine("Before: {0}, {1} ", s1, s2); SwapStrings(ref s1, ref s2); Console.WriteLine("After: {0}, {1} ", s1, s2); Console.ReadLine(); }

Before: Flip, FlopAfter: Flop, Flip

21

Page 22: C#, Visual Studio 2010, .NET 4.0

static double Srednia(params double[] values){ Console.WriteLine(„Ile: {0}", values.Length); double sum = 0; if (values.Length == 0) return sum; for (int i = 0; i < values.Length; i++) sum += values[i]; return (sum / values.Length); }

double average;average = Srednia(4.0, 3.2, 5.7, 64.22, 87.2);Console.WriteLine("Average of data is: {0}", average);

double[] data = { 4.0, 3.2, 5.7 };average = Srednia(data);Console.WriteLine("Average of data is: {0}", average);

22

paramsparams

Page 23: C#, Visual Studio 2010, .NET 4.0

Parametry opcjonalne (.NET Parametry opcjonalne (.NET 4.0)4.0)static void EnterLogData(string message, string

owner = "Programmer"){ Console.Beep(); Console.WriteLine("Error: {0}", message); Console.WriteLine("Owner of Error: {0}", owner);}

static void Main(string[] args){ EnterLogData(„ERROR"); EnterLogData(„ERROR", „Ja"); Console.ReadLine();}

23

Page 24: C#, Visual Studio 2010, .NET 4.0

Wywoływanie metod z nazwanymi Wywoływanie metod z nazwanymi parametrami (.NET 4.0) parametrami (.NET 4.0) - Kolejność wywołania: dowolna

static void Main(string[] args){ Metoda(message: "Test", textColor:

ConsoleColor.DarkRed, BackgroundColor: ConsoleColor.White);

Metoda(backgroundColor: ConsoleColor.Green,

Message:"Testing...",textColor:ConsoleColor.DarkBlue);

Console.ReadLine();}

static void Metoda(ConsoleColor textColor, ConsoleColor backgroundColor, string

message){

...}

24

Page 25: C#, Visual Studio 2010, .NET 4.0

Przeciążenie metodPrzeciążenie metod

static int Add(int x, int y) { return x + y; } static double Add(double x, double y) { return x + y; } static long Add(long x, long y) { return x + y; }

static void Main(string[] args) { Console.WriteLine(""); Console.WriteLine(Add(10, 10)); Console.WriteLine(Add(900000000000, 900000000000)); Console.WriteLine(Add(4.3, 4.4)); Console.ReadLine(); }

25

Page 26: C#, Visual Studio 2010, .NET 4.0

TabliceTabliceint[] myInts = new int[3];myInts[0] = 100;myInts[1] = 200;myInts[2] = 300;

string[] stringArray = new string[] {"raz","dwa","trzy"};

Console.WriteLine("Elementów: {0}", stringArray.Length);

bool[] boolArray = { false, false, true };Console.WriteLine("Elementów: {0}", boolArray.Length);

int[] intArray = new int[4] { 20, 22, 23, 0 };Console.WriteLine("Elementów: {0}", intArray.Length);Console.WriteLine();

26

Page 27: C#, Visual Studio 2010, .NET 4.0

Tablice typu varTablice typu varTablice obiektówTablice obiektów

Console.WriteLine("=> Implicit Array Initialization.");var a = new[] { 1, 10, 100, 1000 };Console.WriteLine("a is a: {0}", a.ToString());var b = new[] { 1, 1.5, 2, 2.5 };Console.WriteLine("b is a: {0}", b.ToString());var c = new[] { "hello", null, "world" };Console.WriteLine("c is a: {0}", c.ToString());Console.WriteLine();

object[] myObjects = new object[4];myObjects[0] = 42;myObjects[1] = false;myObjects[2] = new DateTime(2012, 12, 22);myObjects[3] = "Form & Void";foreach (object obj in myObjects){ Console.WriteLine("Type: {0}, Value: {1}", obj.GetType(),

obj);}

27

Page 28: C#, Visual Studio 2010, .NET 4.0

Tablica postrzępionaTablica postrzępiona(jagged array)(jagged array)

static void JaggedMultidimensionalArray() { int[][] myJagArray = new int[5][]; for (int i = 0; i < myJagArray.Length; i++) myJagArray[i] = new int[i + 7];

for (int i = 0; i < 5; i++) { for (int j = 0; j < myJagArray[i].Length; j++) Console.Write(myJagArray[i][j] + " "); Console.WriteLine(); } Console.WriteLine(); }

0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0

28

Page 29: C#, Visual Studio 2010, .NET 4.0

Typy wyliczenioweTypy wyliczeniowe

enum EmpType : byte

{

Manager = 10,

Grunt = 1,

Contractor = 100,

VicePresident = 999

}

static void Main(string[] args)

{

EmpType emp = EmpType.Contractor;

AskForBonus(emp);

Console.ReadLine();

Console.WriteLine("emp is a {0}.",emp.ToString());

// Wypisze "Contractor = 100".

Console.WriteLine("{0} = {1}", emp.ToString(), (byte)emp);

}

static void AskForBonus(EmpType e)

{

switch (e)

{

case EmpType.Manager:

Console.WriteLine(„A może akcje?");

break;

case EmpType.Grunt:

Console.WriteLine(„Bardzo zabawne...");

break;

case EmpType.Contractor:

Console.WriteLine(„Ty zdzierco...");

break;

case EmpType.VicePresident:

Console.WriteLine(„TAK JEST!”);

break;

}

}

29

Page 30: C#, Visual Studio 2010, .NET 4.0

StrukturyStrukturystruct Point{ public int X; public int Y; public void Increment() { X++; Y++; } public Point(int xP, int yP) { X = xP; Y = yP; } public void Display() { Console.WriteLine("X = {0}, Y = {1}", X,

Y); }}

30

static void Main(string[] args)

{ Point myPoint; myPoint.X = 349; myPoint.Y = 76; myPoint.Display(); myPoint.Increment(); myPoint.Display(); Console.ReadLine();}

Page 31: C#, Visual Studio 2010, .NET 4.0

Inne sposoby pracy z typami Inne sposoby pracy z typami (możliwe w C#)(możliwe w C#)Typy wartościowe zawierające typy

referencyjne ( struct zawierające class )

Przekazywanie typów referencyjnych przez wartość( public void Metoda(Person p) { … } )

Przekazywanie typów referencyjnych przez referencje( ref )

Wiele innych31

Page 32: C#, Visual Studio 2010, .NET 4.0

Typy nullable, operator ??Typy nullable, operator ??int? nullableInt = 10;double? nullableDouble = 3.14;bool? nullableBool = null;char? nullableChar = 'a';int?[] arrayOfNullableInts = new int?[10];

// compile-time error:string? s = "oops";

int? jakasLiczba = Metoda() ?? 100;// jeżeli Metoda() zwróci coś o wartości NULL, wtedy (i tylko wtedy) przypisz wartość 100 do ‘jakasLiczba’

32

Page 33: C#, Visual Studio 2010, .NET 4.0

Część V:Część V:Klasy, obiekty, etc.Klasy, obiekty, etc.

33

Page 34: C#, Visual Studio 2010, .NET 4.0

Przykład klasyPrzykład klasy

class Car { public string petName; public int currSpeed; public void PrintState() { Console.WriteLine

("{0} jedzie {1} kmh.", petName, currSpeed);

}

public void SpeedUp(int delta)

{ currSpeed += delta; } }

class Program{ static void Main(string[]

args) { Car myCar = new Car(); myCar.petName = "Audi"; myCar.currSpeed = 10;

for (int i = 0; i <= 10; i++) {

myCar.SpeedUp(5); myCar.PrintState(); } Console.ReadLine(); }}

34

Page 35: C#, Visual Studio 2010, .NET 4.0

thisthis

public int currSpeed;public Car(int currSpeed){ currSpeed = currSpeed;}

VS:

public Car(int currSpeed){ this.currSpeed = currSpeed;}

35

Page 36: C#, Visual Studio 2010, .NET 4.0

this – wskazanie na this – wskazanie na konstruktorkonstruktor

class Motorcycle{ public int power; public string driverName; public Motorcycle() { } public Motorcycle(int intensity) : this(intensity, "") { } public Motorcycle(string name) : this(0, name) { } public Motorcycle(int pow, string name) { if(pow > 10) { pow = 10; } power = pow; driverName = name; } }

Motorcycle c = new Motorcycle(5); najpierw wykona się najniższy konstruktor (czyli Motorcycle(int

pow, string name) ), dopiero potem ten, który przyjmuje int (z powodu konstrukcji: " : this(intensity, ” ”) { } "

36

Page 37: C#, Visual Studio 2010, .NET 4.0

Konstruktor z domyślnymi Konstruktor z domyślnymi parametrami (.NET 4.0)parametrami (.NET 4.0)

public Motorcycle(int power = 0, string name = "")

{

if (power > 10)

{

power = 10;

}

this.power = intensity;

driverName = name;

}

37

Page 38: C#, Visual Studio 2010, .NET 4.0

staticstaticclass Motorcycle

{

public static int ileMotocykli;

public static int liczbaStworzonychObiektow()

{

return ileMotocykli;

}

}

Dostępne z poziomu klasy, nie obiektu – wszystkie nowe obiekty współdzielą jedną wersję pól statycznych / metod statycznych w ramach swojej klasy.

Tylko metody statyczne i pola statyczne mogą być używane wewnątrz metod statycznych – nie mają one dostępu do zwykłych pól, bo te nie istnieją na tym poziomie (żadnego „this”! ).

38

Page 39: C#, Visual Studio 2010, .NET 4.0

Programowanie obiektowe Programowanie obiektowe (OOP)(OOP)Czyli co należy znać już od dawna:

dziedziczeniepolimorfizmhermetycznośćużywanie obiektów innej klasy w

jeszcze innym obiekcie (jeszcze innej klasy), etc.

virtualoverridesealedabstract

39

Page 40: C#, Visual Studio 2010, .NET 4.0

Modyfikatory dostępuModyfikatory dostępupublic

private ( domyślny )

protected

internal (domyślny )

protected internal

40

Page 41: C#, Visual Studio 2010, .NET 4.0

Właściwości ( properties )Właściwości ( properties )class Employee{ private string empName; private int empID; private float currPay; public string Name { get { return empName; } set { if (value.Length > 30)

Console.WriteLine("Przekroczony limit znakow."); else empName = value; } }

public int ID { get { return empID; } set { empID = value; } } public float Pay { get { return currPay; } set { currPay = value; } }}

41

Page 42: C#, Visual Studio 2010, .NET 4.0

Właściwości (seq.)Właściwości (seq.) modyfikatory dostępności:

public string SSN { get { return empSSN; } protected set { empSSN = value; } }

tylko do odczytu: public string SSN { get { return empSSN; } }

automatyczne: class Car { public string PetName { get; set; } public int Speed { get; set; } public string Color { get; set; } }

42

Page 43: C#, Visual Studio 2010, .NET 4.0

Inicjalizator obiektówInicjalizator obiektówclass Punkt

{

public int X { get; set; }

public int Y { get; set; }

public Punkt(int xVal, int yVal)

{

X = xVal;

Y = yVal;

}

public Punkt() { }

public void ShowData()

{

Console.WriteLine("[{0}, {1}]", X, Y);

}

}

Punkt finalPoint = new Punkt { X = 30, Y = 30 };

Punkt finalPoint2 = new Punkt() { X = 30, Y = 30 };

Punkt pt = new Punkt(10, 16) { X = 100, Y = 100 }; //no i jakie teraz będą współrzędne?

finalPoint.ShowData();

Console.ReadLine();

43

Page 44: C#, Visual Studio 2010, .NET 4.0

Inicjalizator obiektów Inicjalizator obiektów (seq.)(seq.)

class Punkt { public int X { get; set; } public int Y { get; set; } public PointColor Color { get; set; }

public Punkt(int xVal, int yVal) { X = xVal; Y = yVal; } public Punkt() { } public Punkt(PointColor ptColor) { Color = ptColor; } public Punkt() : this(PointColor.BloodRed){ }

public void ShowData() { Console.WriteLine("[{0}, {1}]", X, Y); } } … Punkt goldPoint = new Punkt(PointColor.Gold) { X = 90, Y = 20 };

44

Page 45: C#, Visual Studio 2010, .NET 4.0

StałeStałe const

public const double Pi = 3.14;const string napis = "NAPIS";

readonly

public readonly double PI;…public Klasa() {

PI = 3.14;

}

także: static dodane do powyższych - o ile potrzebujemy stałych statycznych (np. aby móc na nich operować wewnątrz metod statycznych).

45

Page 46: C#, Visual Studio 2010, .NET 4.0

Część VI: Część VI: Dziedziczenie i Dziedziczenie i polimorfizmpolimorfizm

46

Page 47: C#, Visual Studio 2010, .NET 4.0

DziedziczenieDziedziczenie class Samochod { public readonly int limit; private int currSpeed; public Samochod(int max) { limit = max; } public Samochod() { limit = 55; } public int Speed { get { return currSpeed; } set { currSpeed = value; if (currSpeed > limit) { currSpeed = limit; } } } }

class Ciezarowka : Samochod {

}

47

Page 48: C#, Visual Studio 2010, .NET 4.0

Dziedziczenie (seq.)Dziedziczenie (seq.) Brak wielokrotnego dziedziczenia klas (działa dla interfejsów)

SEALED – zamknięcie dalszego dziedziczenia z klasy, którą poprzedzimy właśnie rozkazem ‘sealed’

Załóżmy, że klasa nadrzędna ma 5 pól public arg1 - arg5, dziedzicząca dodała własne arg6, wtedy konstruktor dziedziczącej, żeby się nie powtarzać może wyglądać tak:

public Dziedziczaca(int arg1, int arg2, int arg3, string arg4, string arg5, double arg6) : base (arg1, arg2, arg3, arg4, arg5)

{pole6 = arg6;

}

48

Page 49: C#, Visual Studio 2010, .NET 4.0

Typy zagnieżdżoneTypy zagnieżdżoneclass Zewnetrzna{ public class Wewnetrzna { }

private class JeszczeJednaWewnetrzna { }

}

Cechy:Kontrola takiej klasy (zagnieżdżonej)dostęp do privatetyp pomocniczy

49

Page 50: C#, Visual Studio 2010, .NET 4.0

Polimorfizm: virtual, Polimorfizm: virtual, override, etc.override, etc.

class Przyklad { private int dane = 1; public virtual void Stats() { Console.WriteLine(dane); } }

class Inna : Przyklad { private int inneDane = 10; public override void Stats() { Console.WriteLine(inneDane); } }

Bez słów virtual/override – wystąpi ostrzeżenia środowiska i kompilatora, ale tylko ostrzerzenie (program wciąż można kompilować). Można użyć słówka ‘new’ jako słowa środowiskowego: „odczep się, wiem co robię” – jest to tzw. cieniowanie składowych.

public override sealed void Stats () { … }50

Page 51: C#, Visual Studio 2010, .NET 4.0

abstractabstract Dla klas, które nie mają być tworzone (jako obiekty), ale " tylko "

przekazywać pewną wspólną funkcjonalność dla dziedziczących (które z kolei są już tworzone jako: Obiekt = new Klasa();

W przypadku metod z klasy abstract – WYMUSZONE SĄ przeładowania ich jako override (w przeciwieństwie do przypadku samego virtual/override wewnątrz klasy nie będącej abstrakcyjną, które to rozkazy wtedy nie wymuszają niczego, tj. jeśli klasa dziedzicząca nie przeładuje takiej metody, wtedy może dojść do wywołania metody wirtualnej z klasy bazowej – niekoniecznie będzie to sensowne. Słowo abstract przed tym zabezpiecza ).

Metody abstrakcyjne TYLKO w klasach abstrakcyjnych.

Nie ma ciała metody, tj. zawsze konstrukcja:◦ public abstract void Metoda ( parametry ) {} // ostatnie nawiasy

konieczne, ale puste51

Page 52: C#, Visual Studio 2010, .NET 4.0

as / isas / isKolo kolko = new Kolo();Sprezyna x66 = (Sprezyna)kolko;

// error, InvalidCastException

Powyższą, mało bezpieczną konstrukcję można zastąpić:

try { Hexagon hex = (Hexagon)frank; }

catch (InvalidCastException ex) { Console.WriteLine(ex.Message); }

ALBO przy użyciu słowa AS:

Sprezyna x67 = kolko as Sprezyna; //a nóż-widelec się uda…if (x67 == null) { ... }

IS - skoro słowo as pozwala tworzyć „cuda na kreacją” klas, słowo is pozwala potem ogarnąć, z jakiego rodzaju obiektem (jakiej klasy) mamy do czynienia gdzieś dalej w kodzie:

if ( x67 is kolko ) { . . . } else { . . . }

52

Page 53: C#, Visual Studio 2010, .NET 4.0

Klasa System.Object – pani matka Klasa System.Object – pani matka WSZYSTKIEGO w języku C#WSZYSTKIEGO w języku C#

public class Object{

// Virtual members.public virtual bool Equals(object obj);protected virtual void Finalize();public virtual int GetHashCode();public virtual string ToString();

// Instance level, non-virtual members.public Type GetType();protected object MemberwiseClone();

// Static members.public static bool Equals(object objA, object objB);public static bool ReferenceEquals (object objA, object objB);

}

Krótko i zwięźle: WSZYSTKO, każda klasa, dziedziczy z System.Object albo bezpośrednio, albo pośrednio.

53

Page 54: C#, Visual Studio 2010, .NET 4.0

Część VII: Strukturalna Część VII: Strukturalna obsługa wyjątkówobsługa wyjątków

54

Page 55: C#, Visual Studio 2010, .NET 4.0

System.Exception – główna System.Exception – główna klasa, z której dziedziczą klasa, z której dziedziczą wyjątkiwyjątki public class Exception : ISerializable, _Exception

{ // Public constructors public Exception(string message, Exception innerException); public Exception(string message); public Exception(); // Methods public virtual Exception GetBaseException(); public virtual void GetObjectData(SerializationInfo info, StreamingContext context); // Properties public virtual IDictionary Data { get; } public virtual string HelpLink { get; set; } public Exception InnerException { get; } public virtual string Message { get; } public virtual string Source { get; set; } public virtual string StackTrace { get; } public MethodBase TargetSite { get; } }

55

Page 56: C#, Visual Studio 2010, .NET 4.0

Tworzenie własnego Tworzenie własnego wyjątkuwyjątku

Exception ex = new Exception(string.Format("{0} wylecial w powietrze!", name));

ex.HelpLink = "http://www.costam.pl";ex.Data.Add("Czas", string.Format("Czas: {0}",

DateTime.Now));ex.Data.Add("Powod", "Bo masz pecha.");

throw ex; // ręczne odpalenie wyjątku

56

Page 57: C#, Visual Studio 2010, .NET 4.0

Obsługa wyjątkówObsługa wyjątkówtry{

...; //tutaj coś eksplodowało}catch (Exception e){

Console.WriteLine("Member name: {0}", e.TargetSite);Console.WriteLine("Class defining member: {0}",

e.TargetSite.DeclaringType);Console.WriteLine("Member type: {0}",

e.TargetSite.MemberType); Console.WriteLine("Message: {0}", e.Message);

Console.WriteLine("Source: {0}", e.Source);Console.WriteLine("Stack: {0}", e.StackTrace);Console.WriteLine("Help Link: {0}", e.HelpLink);Console.WriteLine("\n-> Custom Data:");if (e.Data != null){

foreach (DictionaryEntry de in e.Data)Console.WriteLine("-> {0}: {1}", de.Key, de.Value);

}}

57

Page 58: C#, Visual Studio 2010, .NET 4.0

Główne klasy wyjątków:Główne klasy wyjątków:System.Exception

System.SystemException : Exception

System.ApplicationException: Exception

58

Page 59: C#, Visual Studio 2010, .NET 4.0

Własne wyjątki – przykład Własne wyjątki – przykład 22public class CarIsDeadException : ApplicationException

{

private string messageDetails = String.Empty;

public DateTime ErrorTimeStamp { get; set; }

public string CauseOfError { get; set; }

public CarIsDeadException() { }

public CarIsDeadException(string message,

string cause, DateTime time) {

messageDetails = message;

CauseOfError = cause;

ErrorTimeStamp = time;

}

public override string Message {

get { return string.Format("Car Error Message: {0}", messageDetails); }

}

}

WYRZUCENIE WYJĄTKU:

CarIsDeadException ex = new CarIsDeadException (string.Format("{0} wybuchl!", name), „Bo masz pecha", DateTime.Now);

ex.HelpLink = "http://www.allegro.pl";

throw ex;

59

Page 60: C#, Visual Studio 2010, .NET 4.0

Jeszcze lepiej:Jeszcze lepiej: [global::System.Serializable] public class CarIsDeadException : ApplicationException { public CarIsDeadException() { } public CarIsDeadException(string message) : base(message)

{ } public CarIsDeadException(string message, Exception inner)

: base(message, inner) { } protected CarIsDeadException( System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { } public DateTime ErrorTimeStamp { get; set; } public string CauseOfError { get; set; } public CarIsDeadException(string message, string cause, DateTime time) : base(message) { CauseOfError = cause; ErrorTimeStamp = time; } }

60

Page 61: C#, Visual Studio 2010, .NET 4.0

Obsługa wielu wyjątkówObsługa wielu wyjątków try

{

...

}

catch (CarIsDeadException e)

{

Console.WriteLine(e.Message);

}

catch (ArgumentOutOfRangeException e)

{

Console.WriteLine(e.Message);

}

catch (Exception e)

{

Console.WriteLine(e.Message);

}

finally

{

myCar.CrankTunes(false);

}

61

Page 62: C#, Visual Studio 2010, .NET 4.0

Corrupted State Exceptions Corrupted State Exceptions (.NET 4.0)(.NET 4.0)

…czyli tam, gdzie zaczynają się prawdziwe problemy a gdzie słońce już nie dochodzi.

System.Runtime.ExceptionServices -> .NET 4.0 SDK manual

class Program { //bez tego CSE nie zostanie wyłapane: [HandledProcessCorruptedStateExceptions] static int Main(string[] args) { try { //poniższa metoda uruchamia główny program: RunMyApplication(); } catch (Exception ex) { //ten kod niewiele naprawia, ale przynajmniej mówi, na co umarł: Console.WriteLine("Bring out your dead!!! : {0}", ex.Message); return -1; //nawet DOS to zrozumie – etykieta %ERROR% } return 0; //normal program termination } }

62

Page 63: C#, Visual Studio 2010, .NET 4.0

Część VIII:Część VIII:Czas życia obiektówCzas życia obiektów

63

Page 64: C#, Visual Studio 2010, .NET 4.0

Garbage CollectorGarbage CollectorTworzenie obiektów – przez działanie CLR

Brak słowa ‘delete’, można przypisać null referencji, ale… (c.d.)

GC: podział obiektów na generacje 0 – 2, w zależności od tego, jak długo już są w pamięci.

W .NET 4.0 trochę inaczej działa GC niż w 1.0 – 3.5, optymalizacja czyszczenia generacji 0 i generacji 1

64

Page 65: C#, Visual Studio 2010, .NET 4.0

Metody z System.GcMetody z System.Gc AddMemoryPressure()

◦ RemoveMemoryPressure() Collect() CollectionCount() GetGeneration() GetTotalMemory() MaxGeneration() SuppressFinaliza() WaitForPendingFinalizers()

e.g.:◦ GC.GetGeneration(refToObject));

65

Page 66: C#, Visual Studio 2010, .NET 4.0

Garbage Collector (seq.)Garbage Collector (seq.) GC.Collect(); //razem z: GC.WaitForPendingFinalizers(); public enum GCCollectionMode{

Default, //ForcedForced, //collect it nowOptimized //decide when

}

protected virtual void Finalize() // w System.Object

class Klasa { protected override void Finalize() { } //compile-time error ~Klasa() { //destruktor (C++) } }

66

Page 67: C#, Visual Studio 2010, .NET 4.0

Interfejs IDisposableInterfejs IDisposablepublic interface IDisposable { void Dispose();}

Przykład:class JakasKlasa : IDisposable {

public void Dispose() { //clean } }

Wywołanie:static void Main(string[] args) {

JakasKlasa obiekt = new JakasKlasa(); if (obiekt is IDisposable) {

obiekt.Dispose(); } }

67

Page 68: C#, Visual Studio 2010, .NET 4.0

Rozkaz usingRozkaz using JakasKlasa rw = new JakasKlasa(); try {

... } finally { rw.Dispose(); }

I tak dla każdego obiektu?… zgroza. Lepiej:

static void Main(string[] args) {

// Dispose() is called automatically using (JakasKlasa rw = new JakasKlasa())

{ // ... } }

68

Page 69: C#, Visual Studio 2010, .NET 4.0

Finalize + Dispose (a raczej Finalize + Dispose (a raczej LUB)LUB)

class JakasKlasa : IDisposable { ~JakasKlasa() { //czyści i dezynfekuje //nie wywoływać Dispose() po tym } public void Dispose() { //nie wywoływać Finalize po tej metodzie

//(bo po co?), a więc: GC.SuppressFinalize(this); } }

69

Page 70: C#, Visual Studio 2010, .NET 4.0

A najlepiej tak:A najlepiej tak:

class Klasa : IDisposable { private bool disposed = false; public void Dispose() { CleanUp(true); GC.SuppressFinalize(this); } private void CleanUp(bool disposing) { if (this.disposed == false) { if (disposing) {

// Czyszczenie obiektów z pamięci } // Resztę czyścić tutaj } disposed = true; } ~Klasa() { CleanUp(false); } } 70

Page 71: C#, Visual Studio 2010, .NET 4.0

Rise!!! (and eat brains)Rise!!! (and eat brains)public class BaseObj { protected override void Finalize() { Application.ObjHolder = this; }}

class Application { static public Object ObjHolder;

// Defaults to null}

Powyższa metoda WSKRZESZA obiekt. Z tym, że może nam wyjść zombie – jeśli jego podobiekty już naprawdę-naprawdę nie istnieją, a nasz ożywieniec się do nich odwoła – Exception mamy jak w banku (cypryjskim).

71

Page 72: C#, Visual Studio 2010, .NET 4.0

Sztuka nieśmiertelności Sztuka nieśmiertelności c.d.c.d.

public class BaseObj

{

protected override void Finalize()

{

Application.ObjHolder = this;

GC.ReRegisterForFinalize(this);

}

}

Ten obiekt jest nieśmiertelny. Implikacje programistyczne mogą być takie same jak społeczne – totalny bajzel, o ile nie będziemy bardzo ostrożni.

72

Page 73: C#, Visual Studio 2010, .NET 4.0

<Lazy> class (.NET 4.0)<Lazy> class (.NET 4.0) Stwórz obiekt, ale w sumie, to go nie twórz. Przynajmniej

nie do czasu, aż cokolwiek będzie chciało go użyć:

private Lazy<Klasa> mojObiekt = new Lazy<Klasa>();

Poniższe:

private Lazy<Klasa> mojObiekt = new Lazy<Klasa>( () => { return new Klasa(); } );

zawiera wyrażenie Lamba, do obsługi delegata (typu, a jakże: generycznego), który umożliwia zdefiniowanie, którym konstruktorem obiekt ma być utworzony. Pytania?

73

Page 74: C#, Visual Studio 2010, .NET 4.0

Część:Część:IX: InterfejsyIX: Interfejsy

74

Page 75: C#, Visual Studio 2010, .NET 4.0

PrzykładPrzykład class Program

{

static void Main(string[] args) {

// wszystkie 3 klasy obiektów dziedziczą z interfejsu IClonable:

string myStr = "Hello";

OperatingSystem unixOS = new OperatingSystem(PlatformID.Unix, new Version());

System.Data.SqlClient.SqlConnection sqlCnn = new System.Data.SqlClient.SqlConnection();

// więc ich trzy obiekty mogą być posłane w te samą metodę:

CloneMe(myStr);

CloneMe(unixOS);

CloneMe(sqlCnn);

Console.ReadLine();

}

private static void CloneMe(ICloneable c) {

object theClone = c.Clone();

Console.WriteLine("Klon: {0}", theClone.GetType().Name);

}

}

75

Page 76: C#, Visual Studio 2010, .NET 4.0

W interfejsie:W interfejsie: żadnych pól

◦ mogą prototypy właściwości (properties), czyli tylko: int Punkt { get; set; }

żadnych konstruktorów-

żadnych implementacji metod

wszystkie domyślnie public abstract

nie dziedziczą z bazowych ukrytych, choć mogą jawnie z innych bazowych interfejsów

Interfejsy definiują pewne wspólne funkcjonalności, które wszystkie klasy dziedziczące muszą implementować.

76

Page 77: C#, Visual Studio 2010, .NET 4.0

Dziedziczenie, weryfikacja Dziedziczenie, weryfikacja dziedziczeniadziedziczenia z jednego interfejsu z wielu interfejsów z klasy bazowej i interfejsu(ów)

static void Main(string[] args) { Kolo c = new Kolo(); IPunkt itfPt = null; try { itfPt = (IPunkt)c; Console.WriteLine(itfPt.Points); } catch (InvalidCastException e) { Console.WriteLine(e.Message); } Console.ReadLine(); }

77

Page 78: C#, Visual Studio 2010, .NET 4.0

as / is ponownieas / is ponownieKolo kolko = new Kolo();IPointy inter = kolko as IPointy;if (kolko != null){ . . .}else { . . .}

lub:

Kolo kolko = new Kolo();if (kolko is IPointy){ . . .}else { . . .}

78

Page 79: C#, Visual Studio 2010, .NET 4.0

ZastosowaniaZastosowania interface – parametry wejściowe metody

interface – zwracany przez metodę

tablica interfejsów – tj. (jak wyżej z resztą) obiektów klas implementujących danych (wspólny) interfejs

implementacja w VS 2010: zwykła i jawna (wymuszona)

hierarchia interfejsów: dziedziczenie ‘funkcjonalności’ metod abstrakcyjnych interfejsów nadrzędnych

79

Page 80: C#, Visual Studio 2010, .NET 4.0

InterfejsyInterfejsyIEnumerable / IEnumeratorIEnumerable / IEnumerator IEnumerable:

public interface IEnumerable{

IEnumerator GetEnumerator();}

IEnumerator:

public interface IEnumerator{

bool MoveNext (); // następna pozycja ‘kursora’object Current { get;} // pobierz element z kursoravoid Reset (); // kursor na pierwszą pozycję

}

Magic word: yield

80

Page 81: C#, Visual Studio 2010, .NET 4.0

IClonableIClonablepublic interface ICloneable{

object Clone();}

Od programisty zależy, czy to będzie prawdziwa, głęboka kopia (deep-copy, innymi słowy wszystko, łącznie z obiektami potomnymi), czy tylko płytka (shallow-copy)

81

Page 82: C#, Visual Studio 2010, .NET 4.0

IComparable (np. dla funkcji IComparable (np. dla funkcji Sort() )Sort() )

public interface IComparable

{

int CompareTo(object o);

}

Na przykład:

int IComparable.CompareTo(object obj)

{

Car temp = obj as Car;

if (temp != null)

{

if (this.CarID > temp.CarID)

return 1; //cokolwiek >0 – obiekt po aktualnym

if (this.CarID < temp.CarID)

return -1; //cokolwiek mniej niż zero: obiekt przed aktualnym

else

return 0; //te same obiekty

}

else

throw new ArgumentException("!!!!");

}

82

Page 83: C#, Visual Studio 2010, .NET 4.0

IComparerIComparerinterface IComparer{

int Compare(object o1, object o2);}

na przykład:

int IComparer.Compare(object o1, object o2) { Car t1 = o1 as Car; Car t2 = o2 as Car; if (t1 != null && t2 != null) return String.Compare(t1.name, t2.name); else throw new ArgumentException("!!!"); }

zwracanie jako własciwość:

public static IComparer SortByPetName{ get { return (IComparer)new PetNameComparer(); } }

83

Page 84: C#, Visual Studio 2010, .NET 4.0

Część X:Część X:Kolekcje, typy generyczneKolekcje, typy generyczne

84

Page 85: C#, Visual Studio 2010, .NET 4.0

System.Collections (non-System.Collections (non-generic)generic) ArrayList (: IList, ICollection, IEnumerable,

IClonable)

Hashtable (: IDictionary, ICollection, IEnumerable, IClonable)

Queue (FIFO) (: ICollection, IEnumerable, IClonable)

SortedList (: IDictionary, ICollection, IEnumerable, IClonable)

Stack (LIFO) (: ICollection, IEnumerable, IClonable)

85

Page 86: C#, Visual Studio 2010, .NET 4.0

WadyWady wolniejsze niż nowe, typu generic;

niezbyt bezpieczne, przechowują System.Object, więc za każdym razem trzeba się martwić, czy to co wyciągamy z kolekcji na pewno jest odpowiedniego typu;

już od .NET 2.0 weszły kolekcje generyczne, więc warto się w końcu przestawić;

Konkluzja: omijać szeroki łukiem, używać System.Collections.Generic (to samo, tylko „lepiej, szybciej, taniej”)

86

Page 87: C#, Visual Studio 2010, .NET 4.0

Przykład stosowania Przykład stosowania <generic><generic>

static void UseGeneric() { List<Person> morePeople = new List<Person>(); morePeople.Add(new Person("Jan", "Nowak",

30)); Console.WriteLine(morePeople[0]);

List<int> moreInts = new List<int>(); moreInts.Add(1); moreInts.Add(2); int sum = moreInts[0] + moreInts[1];

// Compile-time error: // moreInts.Add(new Person()); }

87

Page 88: C#, Visual Studio 2010, .NET 4.0

Interfejsy kolekcji z pakietuInterfejsy kolekcji z pakietuSystem.Collections.GenerSystem.Collections.Genericic ICollection<T>

IComparer<T>

IDictionary<TKey, TValue>

IEnumerable<T>

IEnumerator<T>

IList <T>

ISet<T>

88

Page 89: C#, Visual Studio 2010, .NET 4.0

Klasy Klasy System.Collections.GenerSystem.Collections.Genericic Dictionary<TKey, TValue>

List<T>

LinkedList<T>

Queue<T>

SortedDictionary<TKey, TValue>

SortedSet<T>

Stack<T>

◦ pakiet System.Core: HastSet<T>

89

Page 90: C#, Visual Studio 2010, .NET 4.0

Inicjalizacja obiektów:Inicjalizacja obiektów:int[] myArrayOfInts = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

};

List<int> myGenericList = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

ArrayList myList = new ArrayList { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

List<Point> myListOfPoints = new List<Point>{

new Point { X = 2, Y = 2 },new Point { X = 3, Y = 3 },new Point(PointColor.BloodRed){ X = 4, Y = 4 }

};

90

Page 91: C#, Visual Studio 2010, .NET 4.0

List<T>List<T>List<Person> people = new List<Person>() {

new Person {FirstName= "Homer", LastName="Simpson", Age=47},new Person {FirstName= "Marge", LastName="Simpson", Age=45},new Person {FirstName= "Lisa", LastName="Simpson", Age=9},new Person {FirstName= "Bart", LastName="Simpson", Age=8}

}; Console.WriteLine("Items in list: {0}", people.Count);

foreach (Person p in people)Console.WriteLine(p);

Console.WriteLine("\n->Inserting new person.");people.Insert(2, new Person { FirstName = "Maggie", LastName = "Simpson",

Age = 2 });Console.WriteLine("Items in list: {0}", people.Count);

Person[] arrayOfPeople = people.ToArray();for (int i = 0; i < arrayOfPeople.Length; i++) {

Console.WriteLine("First Names: {0}",arrayOfPeople[i].FirstName);}

91

Page 92: C#, Visual Studio 2010, .NET 4.0

List<T> wynikList<T> wynikItems in list: 4Name: Homer Simpson, Age: 47Name: Marge Simpson, Age: 45Name: Lisa Simpson, Age: 9Name: Bart Simpson, Age: 8->Inserting new person.Items in list: 5First Names: HomerFirst Names: MargeFirst Names: MaggieFirst Names: LisaFirst Names: Bart

92

Page 93: C#, Visual Studio 2010, .NET 4.0

Stack<T>Stack<T>

Stack<Person> stackOfPeople = new Stack<Person>();stackOfPeople.Push(new Person { FirstName = "Homer", LastName =

"Simpson", Age = 47 });stackOfPeople.Push(new Person { FirstName = "Marge", LastName =

"Simpson", Age = 45 });stackOfPeople.Push(new Person { FirstName = "Lisa", LastName = "Simpson",

Age = 9 });

Console.WriteLine("First person is: {0}", stackOfPeople.Peek());Console.WriteLine("Popped off {0}", stackOfPeople.Pop());Console.WriteLine("\nFirst person is: {0}", stackOfPeople.Peek());Console.WriteLine("Popped off {0}", stackOfPeople.Pop());Console.WriteLine("\nFirst person item is: {0}", stackOfPeople.Peek());Console.WriteLine("Popped off {0}", stackOfPeople.Pop());try {

Console.WriteLine("\nnFirst person is: {0}", stackOfPeople.Peek());Console.WriteLine("Popped off {0}", stackOfPeople.Pop());

}catch (InvalidOperationException ex) {

Console.WriteLine("\nError! {0}", ex.Message);}

93

Page 94: C#, Visual Studio 2010, .NET 4.0

Stack<T> wynikStack<T> wynikFirst person is: Name: Lisa Simpson, Age: 9Popped off Name: Lisa Simpson, Age: 9First person is: Name: Marge Simpson, Age: 45Popped off Name: Marge Simpson, Age: 45First person item is: Name: Homer Simpson,

Age: 47Popped off Name: Homer Simpson, Age: 47Error! Stack empty.

94

Page 95: C#, Visual Studio 2010, .NET 4.0

Queue<T>Queue<T>

Queue<Person> peopleQ = new Queue<Person>();peopleQ.Enqueue(new Person

{ FirstName = "Homer", LastName = "Simpson", Age = 47 });peopleQ.Enqueue(new Person

{ FirstName = "Marge", LastName = "Simpson", Age = 45 });peopleQ.Enqueue(new Person

{ FirstName = "Lisa", LastName = "Simpson", Age = 9 });

Console.WriteLine("{0} is first in line!", peopleQ.Peek().FirstName);

GetCoffee(peopleQ.Dequeue());GetCoffee(peopleQ.Dequeue());GetCoffee(peopleQ.Dequeue());try{ GetCoffee(peopleQ.Dequeue()); }catch (InvalidOperationException e) {

Console.WriteLine("Error! {0}", e.Message); }

95

Page 96: C#, Visual Studio 2010, .NET 4.0

Queue<T> wynikQueue<T> wynik

Homer is first in line!Homer got coffee!Marge got coffee!Lisa got coffee!Error! Queue empty.

96

Page 97: C#, Visual Studio 2010, .NET 4.0

SortedSet<T>SortedSet<T>

class SortPeopleByAge : IComparer<Person>

{public int Compare(Person

firstPerson, Person secondPerson)

{if (firstPerson.Age >

secondPerson.Age)return 1;

if (firstPerson.Age < secondPerson.Age)return -1;

elsereturn 0;

}}

private static void UseSortedSet(){

SortedSet<Person> setOfPeople = new SortedSet<Person>(new SortPeopleByAge()) {

new Person {FirstName= "Homer", LastName="Simpson", Age=47},

new Person {FirstName= "Marge", LastName="Simpson", Age=45},

new Person {FirstName= "Lisa", LastName="Simpson", Age=9},

new Person {FirstName= "Bart", LastName="Simpson", Age=8} };foreach (Person p in setOfPeople) {

Console.WriteLine(p); }Console.WriteLine();

setOfPeople.Add(new Person { FirstName = "Saku", LastName = "Jones", Age = 1 });

setOfPeople.Add(new Person { FirstName = "Mikko", LastName = "Jones", Age = 32 });foreach (Person p in setOfPeople) {

Console.WriteLine(p);}

}

97

Page 98: C#, Visual Studio 2010, .NET 4.0

SortedSet<T> wynikSortedSet<T> wynikName: Bart Simpson, Age: 8Name: Lisa Simpson, Age: 9Name: Marge Simpson, Age: 45Name: Homer Simpson, Age: 47

Name: Saku Jones, Age: 1Name: Bart Simpson, Age: 8Name: Lisa Simpson, Age: 9Name: Mikko Jones, Age: 32Name: Marge Simpson, Age: 45Name: Homer Simpson, Age: 47

98

Page 99: C#, Visual Studio 2010, .NET 4.0

Tworzenie swoich własnych Tworzenie swoich własnych <generic><generic>

np. dla podmiany ze sobą referencji obiektów/struktur DOWOLNEGO typu:

static void Swap<T>(ref T a, ref T b) { T temp; temp = a; a = b; b = temp; } static void DisplayBaseClass<T>() { Console.WriteLine("Base class of {0}: {1}.", typeof(T), typeof(T).BaseType); } Wywołanie:

bool b1 = true, b2 = false;Swap(ref b1, ref b2);

Lepiej jednak tak (większa jaśność dla innych):Swap<bool>(ref b1, ref b2);

99

Page 100: C#, Visual Studio 2010, .NET 4.0

Część XI:Część XI:Delegates, events, Lambda Delegates, events, Lambda expressionsexpressions

100

Page 101: C#, Visual Studio 2010, .NET 4.0

Garść teoriiGarść teorii Do tego miejsca metody coś robiły po tym, jak się je

kopnęło, w ten czy inny sposób.

Idea delegatów i zdarzeń jest taka, żeby metody mogły reagować zwrotnie, tj. same powodować pewne zachowania całego programu, jeśli zaistnieją pewne warunki (dajmy na to: startowe).

Delegat to obiekt, który przechowuje informacje o:◦ metodach, do których ma się odwołać w razie

konieczności◦ ich parametrach wejściowych (typy)◦ ich paramterach wyjściowych (typy)

101

Page 102: C#, Visual Studio 2010, .NET 4.0

public delegate string MyDelegate(bool a, bool b, bool c);

Zmienia się w:

sealed class MyDelegate : System.MulticastDelegate

{

public string Invoke(bool a, bool b, bool c);

public IAsyncResult BeginInvoke(bool a, bool b,

bool c, AsyncCallback cb, object state);

public string EndInvoke(IAsyncResult result);

}

102

Page 103: C#, Visual Studio 2010, .NET 4.0

Przykład:Przykład:public delegate int BinaryOp(int x, int y);

public class SimpleMath{

public static int Add(int x, int y){ return x + y; }public static int Subtract(int x, int y){ return x - y; }

}

class Program{

static void Main(string[] args){

BinaryOp b = new BinaryOp(SimpleMath.Add);Console.WriteLine("10 + 10 is {0}", b(10, 10));Console.ReadLine();

}}

103

Page 104: C#, Visual Studio 2010, .NET 4.0

lista parametrów delagata oraz metod, które zawiera musi się zgadzać i to dokładnie

wyświetlanie zawartości:

static void DisplayDelegateInfo(Delegate delObj)

{

foreach (Delegate d in delObj.GetInvocationList())

{

Console.WriteLine("Method Name: {0}", d.Method);

Console.WriteLine("Type Name: {0}", d.Target);

}

}

104

Page 105: C#, Visual Studio 2010, .NET 4.0

Dodawania i odejmowanie metod do delegata poprzez np. operatory += oraz -= ;

konstrukcja delegatów wspiera generyczność: po ludzku, możliwa konstrukcja jak np. :

public delegate void MyGenericDelegate<T>(T arg);

105

Page 106: C#, Visual Studio 2010, .NET 4.0

EventsEvents{

public delegate void CarEngineHandler(string msg);

public event CarEngineHandler Exploded;public event CarEngineHandler AboutToBlow;

}

Najpierw należy określić delegata, który będzie przetrzymywać metody, które należy wywołać.

Następnie określamy zdarzenia (events), które zamierzamy odpalić (z parametrami zdefiniowanymi jak w delegacie, czyli np. > Exploded("wybuchłem…”); )

Po odpaleniu eventu, odpalany jest delegat, który wykonuje metody, które ma w sobie zawarte, z parametrami jakie dostał event (dlatego musi być zgodność między nimi).

106

Page 107: C#, Visual Studio 2010, .NET 4.0

Część XII:Część XII:Indeksery, przeładowanie Indeksery, przeładowanie operatorówoperatorów

107

Page 108: C#, Visual Studio 2010, .NET 4.0

Indeksery, przykładIndeksery, przykładPeopleCollection myPeople = new PeopleCollection();myPeople[0] = new Person("Homer", "Simpson", 40);myPeople[1] = new Person("Marge", "Simpson", 38);myPeople[2] = new Person("Lisa", "Simpson", 9);myPeople[3] = new Person("Bart", "Simpson", 7);myPeople[4] = new Person("Maggie", "Simpson", 2);for (int i = 0; i < myPeople.Count; i++){

Console.WriteLine("Person number: {0}", i);Console.WriteLine("Name: {0} {1}",myPeople[i].FirstName, myPeople[i].LastName);Console.WriteLine("Age: {0}", myPeople[i].Age);Console.WriteLine();

}

108

Page 109: C#, Visual Studio 2010, .NET 4.0

Przykład, c.d.Przykład, c.d. Jak zdefiniować indekser dla poprzedniego przykładu?

public class PeopleCollection : IEnumerable

{

private ArrayList arPeople = new ArrayList();

public Person this[int index]

{

get { return (Person)arPeople[index]; }

set { arPeople.Insert(index, value); }

}

}

109

Page 110: C#, Visual Studio 2010, .NET 4.0

Indeksowanie po typie Indeksowanie po typie stringstringpublic class PeopleCollection : IEnumerable{

private Dictionary<string, Person> listPeople =new Dictionary<string, Person>();public Person this[string name]{

get { return (Person)listPeople[name]; }set { listPeople[name] = value; }

}IEnumerator IEnumerable.GetEnumerator(){ return listPeople.GetEnumerator(); }

}

czyli w ten sposób:Person homer = myPeople["Homer"];Console.WriteLine(homer.ToString());

110

Page 111: C#, Visual Studio 2010, .NET 4.0

indeksery mogą być przeładowane, tj. kilka różnych dla tego samego obiektu, np. ideksowanie zarówno po liczbach porządkowych jak i po string

mogą być używane wielowymiarowo:

public class SomeContainer

{

private int[ , ] my2DintArray = new int[10, 10];

public int this[int row, int column]

{ /* get / set odpowiednio skonstruowane */ }

} indeksery mogą być definiowane w interfejsach, aby klasy

dziedziczące implementowały odpowiednie metody indeksujące

111

Page 112: C#, Visual Studio 2010, .NET 4.0

Przeciążenie operatorówPrzeciążenie operatorów

Przykład:

public static Point operator +(Point p1, Point p2) { return new Point(p1.X + p2.X, p1.Y + p2.Y); }

Zawsze public, zawsze static (i trzeba to wprost wpisywać w kodzie)

Kolejność parametrów jest ważna przy wywoływaniu (o ile są różnych typów)

Możliwe dla operatorów unarnych (e.g. +, -, ~, !, ++, --), binarnych (+, -, *, /, itd.) i innych

Operatory = i != ; < i >; <= i => MUSZĄ być przeładowane razem w kodzie (i jeden, i drugi).

Niemożliwe dla [], () oraz operatorów skróconych, tj. np. -=, +=, *=, itd.

112

Page 113: C#, Visual Studio 2010, .NET 4.0

Część XIII:Część XIII:WielowątkowośćWielowątkowość

113

Page 114: C#, Visual Studio 2010, .NET 4.0

And now… the delegates And now… the delegates (again)(again)

Delegaty mogą wywoływać metody asynchronicznie

Załóżmy, że mamy delegata:

public delegate int BinaryOp(int x, int y);

Dla niego tworzony jest (niejawnie) obiekt klasy:

public sealed class BinaryOp : System.MulticastDelegate

{

public BinaryOp(object target, uint functionAddress);

public void Invoke(int x, int y);

public IAsyncResult BeginInvoke(int x, int y, AsyncCallback cb, object state);

public int EndInvoke(IAsyncResult result);

}114

Page 115: C#, Visual Studio 2010, .NET 4.0

Delegaci, asynchroniczność, Delegaci, asynchroniczność, c.d.c.d.Gdy delegat z przykładu zostanie

aktywowany, metoda Invoke wykona się synchronicznie, tj. główny wątek aplikacji zostanie zatrzymany do czasu, aż wszystko co delegat miał wykonać, zostanie wykonane.

Na przykład (dalszy slajd) w momencie aktywacji delegata zawierającego metodę, która między innymi wstrzymuje główny wątek aplikacji, wszystkie kolejne polecenia kodu muszą czekać, aż delegat skończy pracować.

115

Page 116: C#, Visual Studio 2010, .NET 4.0

Na początek: synchronicznieNa początek: synchronicznie

static void Main(string[] args)

{

Console.WriteLine("***** Synch Delegate Review *****");

Console.WriteLine("Main() invoked on thread {0}.", Thread.CurrentThread.ManagedThreadId);

BinaryOp b = new BinaryOp(Add);

// Could also write b.Invoke(10, 10):

int answer = b(10, 10);

Console.WriteLine("Doing more work in Main()!");

Console.WriteLine("10 + 10 is {0}.", answer);

Console.ReadLine();

}

static int Add(int x, int y)

{

Console.WriteLine("Add() invoked on thread {0}.",

Thread.CurrentThread.ManagedThreadId);

Thread.Sleep(5000);

return x + y;

}

116

Page 117: C#, Visual Studio 2010, .NET 4.0

No więc co z tą No więc co z tą asynchronicznością??asynchronicznością??

Delegat z przykładu (każdy w zasadzie) ma automatycznie wygenerowane 2 tajemnicze metody:

public IAsyncResult BeginInvoke(int x, int y, AsyncCallback cb, object state);

public int EndInvoke(IAsyncResult result);

Gdzie IAsyncResult to interfejs, dzięki któremu zarządza się wynikiem (a dokładnie oczekiwaniem nań):

public interface IAsyncResult

{

object AsyncState { get; }

WaitHandle AsyncWaitHandle { get; }

bool CompletedSynchronously { get; }

bool IsCompleted { get; }

}117

Page 118: C#, Visual Studio 2010, .NET 4.0

Najłatwiej tak:Najłatwiej tak:

static void Main(string[] args)

{

Console.WriteLine("***** Async Delegate Invocation *****");

Console.WriteLine("Main() invoked on thread {0}.",

Thread.CurrentThread.ManagedThreadId);

// Invoke Add() on a secondary thread.

BinaryOp b = new BinaryOp(Add);

IAsyncResult iftAR = b.BeginInvoke(10, 10, null, null);

Console.WriteLine("Doing more work in Main()!");

int answer = b.EndInvoke(iftAR);

Console.WriteLine("10 + 10 is {0}.", answer);

Console.ReadLine();

}

Linia int answer = b.EndInvoke(iftAR); odpowiada za to, żeby nie kazać głównemu wątkowi wyświetlić wyniku, jeśli go jeszcze nie ma (w przykładzie to raczej nie jest trudne, ale jeśli np. w delegacie będzie zadanie ściągnięcia pół giga kontrabandy z internetu, to już może trochę potrwać…)

118

Page 119: C#, Visual Studio 2010, .NET 4.0

Jak stwierdzić, czy delegat Jak stwierdzić, czy delegat skończył?skończył?

Problem oczywiście jest taki, że wciąż program może w przykładzie marnować czas, jeśli między wywołaniem delegata a oczekiwaniem na wynik (EndInvoke) zadania skończą się wcześnie, tak więc można użyć:

BinaryOp b = new BinaryOp(Add);

IAsyncResult iftAR = b.BeginInvoke(10, 10, null, null);

while(!iftAR.IsCompleted)

{

Console.WriteLine("Doing more work in Main()!");

Thread.Sleep(1000);

}

int answer = b.EndInvoke(iftAR);

119

Page 120: C#, Visual Studio 2010, .NET 4.0

Oddzwonimy do pana, jak Oddzwonimy do pana, jak skończymy…skończymy… Jeszcze inaczej:

while (!iftAR.AsyncWaitHandle.WaitOne(1000, true))

{

Console.WriteLine("Doing more work in Main()!");

}

Jeszcze inteligentniej (=jeszcze trudniej) – a może by tak oprócz wątku głównego aplikacji (1), w trakcie pracy którego asynchronicznie robi coś delegat w wątku (2), zaprząc do pracy TRZECI wątek (3), który będzie sprawdzać co robi (2), i jak stwierdzi, że (2) skończył, da informację (1), że ma jakieś wyniki do obsłużenia ? Można oczywiście:

120

Page 121: C#, Visual Studio 2010, .NET 4.0

public delegate int BinaryOp(int x, int y);

class Program {

private static bool isDone = false;

static void Main(string[] args)

{

BinaryOp b = new BinaryOp(Add);

IAsyncResult iftAR = b.BeginInvoke(10, 10, new AsyncCallback(AddComplete), null);

while (!isDone) {

Thread.Sleep(1000);

Console.WriteLine("Working....");

}

Console.ReadLine();

static int Add(int x, int y)

{

Thread.Sleep(5000);

return x + y;

}

static void AddComplete(IAsyncResult itfAR)

{

Console.WriteLine("Your addition is complete"); isDone = true;

}

} 121

Page 122: C#, Visual Studio 2010, .NET 4.0

C.d.C.d. Poprzedni obiekt KLASY AsyncCallback nie miał

dostępu do delagata, który miał monitorować – robił tylko za posłańca z wiadomością, że monitorowany obiekt skończył. Aby uzyskać dostęp do monitorowanego delagata (i jego wyników) należy użyć takiej metody AddComplete() dla poprzedniego przykładu:

static void AddComplete(IAsyncResult itfAR){

AsyncResult ar = (AsyncResult)itfAR; //rzutowanieBinaryOp b = (BinaryOp)ar.AsyncDelegate;Console.WriteLine("10 + 10 is {0}.", b.EndInvoke(itfAR));isDone = true;

}

122

Page 123: C#, Visual Studio 2010, .NET 4.0

Stan obiektuStan obiektuIAsyncResult iftAR = b.BeginInvoke(10, 10, new AsyncCallback(AddComplete),null);

mamy ostatni tajemniczy null pod koniec. Definicja metody to:

public IAsyncResult BeginInvoke(int x, int y, AsyncCallback cb, object state); tak więc chodzi o stan monitorowanego procesu.Dla przykładu, jeśli wywołanie delegata to:

IAsyncResult iftAR = b.BeginInvoke(10, 10, new AsyncCallback(AddComplete), "Dzięki za dodanie tych dwóch liczb");

Wtedy możemy to odtworzyć poprzez: static void AddComplete(IAsyncResult itfAR) {

...

string msg = (string)itfAR.AsyncState;

Console.WriteLine(msg);

isDone = true; } 123

Page 124: C#, Visual Studio 2010, .NET 4.0

Prawdziwa wielowątkowość: Prawdziwa wielowątkowość: System.ThreadingSystem.Threading

Przykład kilku właściwości obiektu z Thread:static void Main(string[] args)

{

Thread primaryThread = Thread.CurrentThread;

primaryThread.Name = "ThePrimaryThread"; //!!!! Przydatne do debugowania

Console.WriteLine("Name of current AppDomain: {0}",Thread.GetDomain().FriendlyName);

Console.WriteLine("ID of current Context: {0}",Thread.CurrentContext.ContextID);

Console.WriteLine("Thread Name: {0}",primaryThread.Name);

Console.WriteLine("Has thread started?: {0}",primaryThread.IsAlive);

Console.WriteLine("Priority Level: {0}",primaryThread.Priority);

Console.WriteLine("Thread State: {0}",primaryThread.ThreadState);

Console.ReadLine();

}

Wynik:Name of current AppDomain: ThreadStats.exe

ID of current Context: 0

Thread Name: ThePrimaryThread

Has thread started?: True

Priority Level: Normal // enum ThreadPriority – nie jest to obligatoryjne dla środowiska

Thread State: Running

124

Page 125: C#, Visual Studio 2010, .NET 4.0

Przykład (1)Przykład (1) Mamy drukarkę, która coś tam… drukuje

(niespodzianka): public class Printer

{

public void PrintNumbers()

{

Console.WriteLine("-> {0} is executing PrintNumbers()", Thread.CurrentThread.Name);

Console.Write("Your numbers: ");

for (int i = 0; i < 10; i++)

{

Console.Write("{0}, ", i);

Thread.Sleep(2000);

}

Console.WriteLine();

}

}

125

Page 126: C#, Visual Studio 2010, .NET 4.0

Główny kod:Główny kod:static void Main(string[] args) { Printer p = new Printer(); Thread backgroundThread = new Thread(new ThreadStart(p.PrintNumbers));

backgroundThread.Name = "Secondary"; backgroundThread.Start(); }

Po ostatnim poleceniu całość działań obiektu drukarki będzie realizowana w osobnym wątku, więc jeśli będą dalsze polecenia po backgroundThread.Start(), to spokojnie się zrealizują.Ważna jest liczba rdzeni CPU! Na jednoprocesorowym komputerze program będzie bardziej „responsywny”, ale na pewno nie szybszy!

126

Page 127: C#, Visual Studio 2010, .NET 4.0

c.d.c.d. ThreadStart() może przyjmować tylko metody zwracające void i nie

przejmujące żadnych argumentów – czyli tak trochę biednie. Przykład:class AddParams {

public int a, b;

public AddParams(int numb1, int numb2) {

a = numb1;

b = numb2;

}

}

Oraz metoda statyczna:static void Add(object data)

{

if (data is AddParams)

{

AddParams ap = (AddParams)data;

Console.WriteLine("{0} + {1} is {2}", ap.a, ap.b, ap.a + ap.b);

}

}

127

Page 128: C#, Visual Studio 2010, .NET 4.0

Realizacja wątku z Realizacja wątku z poprzedniego slajdu:poprzedniego slajdu:AddParams ap = new AddParams(10, 10);

Thread t = new Thread(new ParameterizedThreadStart(Add));

t.Start(ap);

// Force a wait to let other thread finish.

Thread.Sleep(5);

Console.ReadLine();

128

Page 129: C#, Visual Studio 2010, .NET 4.0

Wątki pierwszo i Wątki pierwszo i drugoplanowedrugoplanowe Wątki pierwszoplanowe muszą zostać (wszystkie)

zakończone, aby środowisko .NET wyładowało z pamięci aplikację (np. metoda Main – dopóki jej ostatnia linia się nie wykona, aplikacja działa).

Wątki drugoplanowe (czasem zwane demonami (linux?)) są kończone, jeżeli zakończył się ostatni wątek pierwszoplanowy. Na przykład: jeśli poprzez polecenie:

jakiśWątek.IsBackground = true;

ustawiamy drugoplanowość „jakiegośWątku”, to niezależnie, czy zakończył on już swoje zadanie czy nie(!), zostanie wyładowany z systemu przez środowisko .NET, jeżeli ostatni wątek pierwszoplanowy został właśnie zakończony.

129

Page 130: C#, Visual Studio 2010, .NET 4.0

Synchronizacja, czyli Synchronizacja, czyli wszyscy na raz, a każdy co wszyscy na raz, a każdy co innego…innego…public void PrintNumbers()

{

lock (threadLock)

{

Console.Write("Your numbers: ");

for (int i = 0; i < 10; i++)

{

Random r = new Random();

Thread.Sleep(1000 * r.Next(5));

Console.Write("{0}, ", i);

}

Console.WriteLine();

}

}

Załóżmy, że gdzieś w kodzie mamy private object threadLock = new Object(); służący jako token blokady, to wszystko wewnątrz kodu lock{ …} będzie wykonywane na raz dla jednego wątku.

130

Page 131: C#, Visual Studio 2010, .NET 4.0

c.d.c.d. Inaczej: jeśli poprzedni kod nie zawierałby klauzuli

lock(coś) { … }, lecz tylko te polecenia co drukują liczby, wtedy, jeśli stworzylibyśmy np. 10, 20 czy 100 takich wątków i uruchomili wszystkie równocześnie, to każdy w swoim czasie coś by tam drukował, jednocześnie na tej samej konsoli. Czyli wyświetlane liczby od 1 do 10 szybko by się wymieszały na ekranie.

Jeśli mamy klauzulę lock z jakimś obiektem robiącym za token, to nawet jeśli mamy 100 takich samych wątków, wtedy pierwszy, który natrafia na lock realizuje go DO KOŃCA po czym dopiero wtedy wątek drugi, trzeci i kolejne w ten sam sposób będą wykonywane.

Jeszcze innymi słowy nadal są to wątki pracujące w tle, ale przynajmniej nie jeden przez drugiego, tylko w kolejności (ale ta kolejność dotyczy tylko realizacji poleceń wewnątrz lock(token) { … } !

131

Page 132: C#, Visual Studio 2010, .NET 4.0

Lock = Lock = System.Threading.MonitorSystem.Threading.MonitorPoprzedni kod, a raczej klazula lock jest

niejawnie zamienia na:public void PrintNumbers() {

Monitor.Enter(threadLock);

try

{

}

finally

{

Monitor.Exit(threadLock);

}

}

Lock(){} jest szybsze do zapisania, ale użycie Monitora daje dostęp do większej liczby metod, np. nakazujących czekać głównemu wątkowi, czy informujących wątki poboczne, że coś się dzieje, np. aktualny kończy pracę.

132

Page 133: C#, Visual Studio 2010, .NET 4.0

Inne formy synchronizacjiInne formy synchronizacjiSystem.Threading.Interlocked – dla

pewnych atomowych poleceń, jak inkremencja czy dekrementacja zmiennej o 1, bezpieczne porównanie i zamiana kolejności dwóch wartości, itd. ◦ np. int zmienna = Interlocked.Increment(ref

innaZmienna);

Atrybut [Synchronization]

Inne zagadnienia: BackgroundWorker, delegat TimeCallback, pula wątków CLR: (ThreadPool.QueueUserWorkItem(WaitCallback wcb) )

133

Page 134: C#, Visual Studio 2010, .NET 4.0

TaskParallelLibrary TaskParallelLibrary (TPL) .NET 4.0(TPL) .NET 4.0Nie znaczy to, że Thread czy asynchroniczne

delegaty stały się passe, i należy przestać ich używać (jak np. kolekcje bez <generic> ) – są i będą wciąż przydatne i nikt nie będzie z nich rezygnować (zbyt szybko).

TPL jest „po prostu” wielką armatą, którą wytaczać należy tylko do NAPRAWDĘ skomplikowanych wielowątkowych algorytmów, których użycie ma szansę znacząco skrócić wykonywanie zadań. Bazuje wciąż na starych technikach tutaj zaprezentowanych, więc ich znajomość jest niezbędna w zrozumieniu TPL.

134

Page 135: C#, Visual Studio 2010, .NET 4.0

Cap. XIV: Pliki, I/O, Cap. XIV: Pliki, I/O, serializacjaserializacja

135

Page 136: C#, Visual Studio 2010, .NET 4.0

System.IOSystem.IO Ważniejsze klasy: BinaryReader BinaryWriter

Directory DirectoryInfo File FileInfo FileStream FileSystemWatcher MemoryStream Path StreamWriter StreamReader StringWriter StringReader

abstract FileSystemInfo:◦ Attributes atrybuty pliku / katalogu

◦ CreationTime czas utworzenia

◦ Exists czy obiekt istnieje?

◦ Extension rozszerzenie

◦ FullName pełna ścieżka dostępu

◦ LastAccessTime ostatni dostęp

◦ LastWriteTime ostatnia modyfikacja

◦ Name nazwa pliku / katalogu

136

Page 137: C#, Visual Studio 2010, .NET 4.0

c.d.c.d. DirectoryInfo:

◦ Create()

◦ CreateSubdirectory() tworzenie katalogu lub zbioru podkatalogów

◦ Delete() kasuje katalog i całą zawartość

◦ GetDirectories() tablica obiektów DirectoryInfo o zawartości katalogu

◦ GetFiles() tablica FileInfo z zawartości katalogu

◦ MoveTo() przenoszenie do nowej ścieżki

◦ Parent zwraca katalog nadrzędny

◦ Root zwraca ścieżkę do korzenia katalogu

// Bind to the current working directory. DirectoryInfo dir1 = new DirectoryInfo("."); // Bind to C:\Windows, // using a verbatim string. DirectoryInfo dir2 = new DirectoryInfo(@"C:\Windows");

137

Page 138: C#, Visual Studio 2010, .NET 4.0

Przykład:DirectoryInfo dir = new DirectoryInfo(@"C:\Windows");Console.WriteLine("***** Directory Info *****");Console.WriteLine("FullName: {0}", dir.FullName);Console.WriteLine("Name: {0}", dir.Name);Console.WriteLine("Parent: {0}", dir.Parent);Console.WriteLine("Creation: {0}", dir.CreationTime);Console.WriteLine("Attributes: {0}", dir.Attributes);Console.WriteLine("Root: {0}", dir.Root);Console.WriteLine("**************************\n");

Wynik:***** Directory Info *****FullName: C:\WindowsName: WindowsParent:Creation: 7/13/2009 10:20:08 PMAttributes: DirectoryRoot: C:\**************************

138

Page 139: C#, Visual Studio 2010, .NET 4.0

Pobieranie listy plików:Pobieranie listy plików:

DirectoryInfo dir = new DirectoryInfo(@"C:\Windows\Web\Wallpaper");

// pobierz wszystkie pliki jpg:

FileInfo[] imageFiles = dir.GetFiles("*.jpg", SearchOption.AllDirectories);

// ile znaleziono? :

Console.WriteLine("Found {0} *.jpg files\n", imageFiles.Length);

foreach (FileInfo f in imageFiles)

{

Console.WriteLine("File name: {0}", f.Name);

Console.WriteLine("File size: {0}", f.Length);

Console.WriteLine("Creation: {0}", f.CreationTime);

Console.WriteLine("Attributes: {0}", f.Attributes);

}

139

Page 140: C#, Visual Studio 2010, .NET 4.0

Tworzenie podkatalogów:Tworzenie podkatalogów:

DirectoryInfo dir = new DirectoryInfo(@"C:\");

dir.CreateSubdirectory("MyFolder");

DirectoryInfo myDataFolder = dir.CreateSubdirectory(@"MyFolder2\Data");

Console.WriteLine("New Folder is: {0}", myDataFolder);

140

Page 141: C#, Visual Studio 2010, .NET 4.0

// lista dysków:

string[] drives = Directory.GetLogicalDrives();

Console.WriteLine("Here are your drives:");

foreach (string s in drives)

Console.WriteLine("--> {0} ", s);

// kasowanie:

try

{

Directory.Delete(@"C:\MyFolder");

// drugie „true” oznacza zgodę na automatyczne kasowanie podkatalogów

Directory.Delete(@"C:\MyFolder2", true);

}

catch (IOException e)

{

Console.WriteLine(e.Message);

}

141

Page 142: C#, Visual Studio 2010, .NET 4.0

static void Main(string[] args) {

// pobranie tablicy obiektów – napędów:

DriveInfo[] myDrives = DriveInfo.GetDrives();

// wyświetlanie informacji

foreach(DriveInfo d in myDrives) {

Console.WriteLine("Name: {0}", d.Name);

Console.WriteLine("Type: {0}", d.DriveType);

// jeśli napęd jest podpięty (DVD, CD, pendrive…)

if(d.IsReady)

{

Console.WriteLine("Free space: {0}", d.TotalFreeSpace);

Console.WriteLine("Format: {0}", d.DriveFormat);

Console.WriteLine("Label: {0}", d.VolumeLabel);

Console.WriteLine();

}

}

Console.ReadLine();

}

142

Page 143: C#, Visual Studio 2010, .NET 4.0

Klasa FileInfo:Klasa FileInfo:static void Main(string[] args)

{

// utworzenie nowego pliku:

FileInfo f2 = new FileInfo(@"C:\Test2.dat");

using(FileStream fs2 = f2.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))

{

//..

}

}

FileMode: CreateNew,Create,Open,OpenOrCreate,Truncate,Append

FileAccess: Read,Write,ReadWrite

FileShare: Delete,Inheritable,None,Read,ReadWrite,Write

143

Page 144: C#, Visual Studio 2010, .NET 4.0

FileInfo.OpenRead() FileInfo.OpenRead() FileInfo.OpenWrite()FileInfo.OpenWrite()static void Main(string[] args)

{

FileInfo f3 = new FileInfo(@"C:\Test3.dat");

using(FileStream readOnlyStream = f3.OpenRead())

{

// FileStream object...

}

// tylko do zapisu:

FileInfo f4 = new FileInfo(@"C:\Test4.dat");

using(FileStream writeOnlyStream = f4.OpenWrite())

{

// FileStream object...

}

}

144

Page 145: C#, Visual Studio 2010, .NET 4.0

FileInfo.OpenText(), FileInfo.CreateText(), FileInfo.OpenText(), FileInfo.CreateText(), FileInfo.AppendText()FileInfo.AppendText()FileInfo f5 = new FileInfo(@"C:\boot.ini");

using(StreamReader sreader = f5.OpenText())

{

// Use the StreamReader object...

}

FileInfo f6 = new FileInfo(@"C:\Test6.txt");

using(StreamWriter swriter = f6.CreateText())

{

// Use the StreamWriter object...

}

FileInfo f7 = new FileInfo(@"C:\FinalTest.txt");

using(StreamWriter swriterAppend = f7.AppendText())

{

// Use the StreamWriter object...

}

145

Page 146: C#, Visual Studio 2010, .NET 4.0

Klasa FileKlasa Fileusing(FileStream fs = File.Create(@"C:\Test.dat"))

{}

using(FileStream fs2 = File.Open(@"C:\Test2.dat",FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))

{}

using(FileStream readOnlyStream = File.OpenRead(@"Test3.dat"))

{}

using(FileStream writeOnlyStream = File.OpenWrite(@"Test4.dat"))

{}

using(StreamReader sreader = File.OpenText(@"C:\boot.ini"))

{}

using(StreamWriter swriter = File.CreateText(@"C:\Test6.txt"))

{}

using(StreamWriter swriterAppend = File.AppendText(@"C:\FinalTest.txt"))

{}

146

Page 147: C#, Visual Studio 2010, .NET 4.0

Inne metody klasy FileInne metody klasy File◦ ReadAllBytes() – tablica bajtów + zamknięcie pliku

◦ ReadAllLines() – tablica strings + zamknięcie pliku

◦ ReadAllText() System.String+ zamknięcie pliku

Poniżej jak wyżej, tylko że zapisujemy coś:

◦ WriteAllBytes()

◦ WriteAllLines()

◦ WriteAllText()

147

Page 148: C#, Visual Studio 2010, .NET 4.0

Przykład:Przykład:static void Main(string[] args)

{

string[] myTasks = {

„Naprawić kran", „Zadzwonić",

„Zjeść coś", „Zagrać w Diablo III"};

// zapis danych:

File.WriteAllLines(@"C:\tasks.txt", myTasks);

// odczyt danych

foreach (string task in File.ReadAllLines(@"C:\tasks.txt"))

{

Console.WriteLine("TODO: {0}", task);

}

Console.ReadLine();

}

148

Page 149: C#, Visual Studio 2010, .NET 4.0

FileStreamFileStream// Obtain a FileStream object.

using(FileStream fStream = File.Open(@"C:\myMessage.dat", FileMode.Create))

{

// zakodowanie wiadomości jako ciągu bajtów

string msg = "Hello!";

byte[] msgAsByteArray = Encoding.Default.GetBytes(msg);

// zapis tablicy bajtów[]

fStream.Write(msgAsByteArray, 0, msgAsByteArray.Length);

// reset położenia „kursora” zapisu

fStream.Position = 0;

// odczyt od „kursora”

Console.Write("Your message as an array of bytes: ");

byte[] bytesFromFile = new byte[msgAsByteArray.Length];

for (int i = 0; i < msgAsByteArray.Length; i++)

{

bytesFromFile[i] = (byte)fStream.ReadByte();

Console.Write(bytesFromFile[i]);

}

Console.WriteLine(Encoding.Default.GetString(bytesFromFile));

}

149

Page 150: C#, Visual Studio 2010, .NET 4.0

Trochę łatwiej (i popularniej jeśli chodzi o Trochę łatwiej (i popularniej jeśli chodzi o stosowanie): StreamWriter i StreamReaderstosowanie): StreamWriter i StreamReaderusing(StreamWriter writer = File.CreateText("reminders.txt"))

{

writer.WriteLine(„Tekst pierwszy");

writer.WriteLine(„Tekst drugi");

writer.WriteLine(„Ciąg liczb:");

for(int i = 0; i < 10; i++)

writer.Write(i + " ");

// nowa linia:

writer.Write(writer.NewLine);

}

using(StreamReader sr = File.OpenText("reminders.txt"))

{

string input = null;

while ((input = sr.ReadLine()) != null)

{

Console.WriteLine (input);

}

}

150

Page 151: C#, Visual Studio 2010, .NET 4.0

Inna wersja z poprzedniego Inna wersja z poprzedniego przykładu:przykładu:// zapis:

using(StreamWriter writer = new StreamWriter("reminders.txt"))

{

...

}

// odczyt:

using(StreamReader sr = new StreamReader("reminders.txt"))

{

...

}

151

Page 152: C#, Visual Studio 2010, .NET 4.0

BinaryWriter i BinaryWriter i BinaryReaderBinaryReaderFileInfo f = new FileInfo("BinFile.dat");

using(BinaryWriter bw = new BinaryWriter(f.OpenWrite()))

{

Console.WriteLine("Base stream is: {0}", bw.BaseStream);

// dane:

double aDouble = 1234.67;

int anInt = 34567;

string aString = "A, B, C";

// zapis danych:

bw.Write(aDouble);

bw.Write(anInt);

bw.Write(aString);

}

using(BinaryReader br = new BinaryReader(f.OpenRead()))

{

Console.WriteLine(br.ReadDouble());

Console.WriteLine(br.ReadInt32());

Console.WriteLine(br.ReadString());

}

152

Page 153: C#, Visual Studio 2010, .NET 4.0

FileSystemWatcherFileSystemWatcherKlasa zawiera metody do

monitorowania co się dzieje z plikiem (tadam, tadam!): asynchronicznie

Np. utworzenie takiego obiektu to:

FileSystemWatcher watcher = new FileSystemWatcher();

try {

watcher.Path = @"C:\MyFolder";

}

catch(ArgumentException ex) {

Console.WriteLine(ex.Message);

return;

}

153

Page 154: C#, Visual Studio 2010, .NET 4.0

c.d.c.d.Co ma być monitorowane i jak:// Set up the things to be on the lookout for.

watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;

// Only watch text files.

watcher.Filter = "*.txt";

// Add event handlers.

watcher.Changed += new FileSystemEventHandler(OnChanged);

watcher.Created += new FileSystemEventHandler(OnChanged);

watcher.Deleted += new FileSystemEventHandler(OnChanged);

watcher.Renamed += new RenamedEventHandler(OnRenamed);

// Begin watching the directory.

watcher.EnableRaisingEvents = true;

// TUTAJ INNY KOD, KTÓRY ROBI JUŻ W PROGRAMIE CO INNEGO, ALE WATCHER DZIAŁA, I JEŚLI COŚ SIĘ STANIE Z PLIKIEM CO ZOSTAŁO OKREŚLONE WYŻEJ, ODPALI SIĘ ODPOWIEDNIA Z METOD NIŻEJ:

Metody:static void OnChanged(object source, FileSystemEventArgs e)

{

Console.WriteLine("File: {0} {1}!", e.FullPath, e.ChangeType);

}

static void OnRenamed(object source, RenamedEventArgs e)

{

Console.WriteLine("File: {0} renamed to\n{1}", e.OldFullPath, e.FullPath);

}

154

Page 155: C#, Visual Studio 2010, .NET 4.0

Serializacja:Serializacja:Poprzednie metody zapisu i odczytu plików

są ok. i powszechnie stosowane. Problem pojawia się, kiedy nieokreśloną (np. na poziomie projektowania czegoś) liczbę parametrów aplikacji trzeba będzie zapisywać, odczytywać, itd. Dla każdego parametru należałoby wtedy wprowadzać osobne linie kodu obsługujące jego zapis/odczyt.

155

Page 156: C#, Visual Studio 2010, .NET 4.0

Przykład serializacji:Przykład serializacji:[Serializable]

public class UserPrefs {

public string WindowColor;

public int FontSize;

}

static void Main(string[] args)

{

UserPrefs userData= new UserPrefs();

userData.WindowColor = "Yellow";

userData.FontSize = "50";

BinaryFormatter binFormat = new BinaryFormatter();

// zapis obiektu w pliku:

using(Stream fStream = new FileStream("user.dat", FileMode.Create, FileAccess.Write, FileShare.None))

{

binFormat.Serialize(fStream, userData);

}

Console.ReadLine();

}156

Page 157: C#, Visual Studio 2010, .NET 4.0

Co serializować a co nie (instrukcje Co serializować a co nie (instrukcje w kodzie, a nie porady życiowe)w kodzie, a nie porady życiowe)[Serializable]

public class Radio

{

public bool hasTweeters;

public bool hasSubWoofers;

public double[] stationPresets;

[NonSerialized]

public string radioID = "XF-552RR6";

}

[Serializable]

public class Car

{

public Radio theRadio = new Radio();

public bool isHatchBack;

}

[Serializable]

public class JamesBondCar : Car

{

public bool canFly;

public bool canSubmerge;

}

157

Page 158: C#, Visual Studio 2010, .NET 4.0

Kolejna informacja co będzie Kolejna informacja co będzie a co nie będzie serializowanea co nie będzie serializowaneBinaryFormatter lub SoapFormatter – te

narzędzia serializują WSZYSTKO co podpada pod tag [serializable] w kodzie, tj. niezależnie czy są to pola publiczne, prywatne, publiczne właściwości prywatne, itd.

XmlSerializer – trochę inaczej. Będzie serializować tylko pola publiczne a także (uwaga!) prywatne dane które zostały udostępnione jako publiczne właściwości (czyli zmienna jeśli nawet jest private, to jeśli jej właściwość get jest publiczna, zostanie przez XmlSerializer przetworzona).

158

Page 159: C#, Visual Studio 2010, .NET 4.0

[Serializable]

public class Person

{

// A public field.

public bool isAlive = true;

// A private field.

private int personAge = 21;

// Public property/private data.

private string fName = string.Empty;

public string FirstName

{

get { return fName; }

set { fName = value; }

}

}

159

Page 160: C#, Visual Studio 2010, .NET 4.0

Różnice serializatorówRóżnice serializatorówBinaryFormatter – jak nazwa wskazuje,

zapisuje binarnie, czyli np. liczba zapisana jest szesnastkowo, a nie w formie tekstu

SoapFormatter – jako wiadomość typu SOAP (XMLowy format przesyłania wiadomości w web service’ach)

XmlSerializer – XML, jak nazwa wskazuje, czyli otagowany całkowicie

160

Page 161: C#, Visual Studio 2010, .NET 4.0

Przykład serializacji Przykład serializacji binarnej:binarnej:

static void Main(string[] args)

{

JamesBondCar jbc = new JamesBondCar(); //4 slajdy wcześniej

jbc.canFly = true;

jbc.canSubmerge = false;

jbc.theRadio.stationPresets = new double[]{89.3, 105.1, 97.1};

jbc.theRadio.hasTweeters = true;

// zapis do pliku:

BinaryFormatter binFormat = new BinaryFormatter();

using(Stream fStream = new FileStream("CarData.dat", FileMode.Create, FileAccess.Write, FileShare.None)) {

binFormat.Serialize(fStream, jbc);

}

//odczyt:

BinaryFormatter binFormat = new BinaryFormatter();

using(Stream fStream = File.OpenRead("CarData.dat")))

{

JamesBondCar carFromDisk = (JamesBondCar)binFormat.Deserialize(fStream);

Console.WriteLine("Can this car fly? : {0}", carFromDisk.canFly);

}

161

Page 162: C#, Visual Studio 2010, .NET 4.0

Zapis listy obiektówZapis listy obiektów[Serializable,

XmlRoot(Namespace = "http://www.MyCompany.com")]

public class JamesBondCar : Car

{

public JamesBondCar(bool skyWorthy, bool seaWorthy)

{

canFly = skyWorthy;

canSubmerge = seaWorthy;

}

// XmlSerializer WYMAGA domyślnego konstruktora!

public JamesBondCar(){}

}

162

Page 163: C#, Visual Studio 2010, .NET 4.0

static void SaveListOfCars()

{

// Now persist a List<T> of JamesBondCars.

List<JamesBondCar> myCars = new List<JamesBondCar>();

myCars.Add(new JamesBondCar(true, true));

myCars.Add(new JamesBondCar(true, false));

myCars.Add(new JamesBondCar(false, true));

myCars.Add(new JamesBondCar(false, false));

using(Stream fStream = new FileStream("CarCollection.xml", FileMode.Create, FileAccess.Write, FileShare.None))

{

XmlSerializer xmlFormat = new XmlSerializer(typeof(List<JamesBondCar>));

xmlFormat.Serialize(fStream, myCars);

}

}

// LUB:static void SaveListOfCarsAsBinary()

{

// Save ArrayList object (myCars) as binary.

List<JamesBondCar> myCars = new List<JamesBondCar>();

BinaryFormatter binFormat = new BinaryFormatter();

using(Stream fStream = new FileStream("AllMyCars.dat", FileMode.Create, FileAccess.Write, FileShare.None))

{

binFormat.Serialize(fStream, myCars);

}

}

163

Page 164: C#, Visual Studio 2010, .NET 4.0

ISerializableISerializable[Serializable]

class StringData : ISerializable

{

private string dataItemOne = "First data block";

private string dataItemTwo= "More data";

public StringData(){}

protected StringData(SerializationInfo si, StreamingContext ctx)

{

//zawsze odczytuj mały literami

dataItemOne = si.GetString("First_Item").ToLower();

dataItemTwo = si.GetString("dataItemTwo").ToLower();

}

void ISerializable.GetObjectData(SerializationInfo info, StreamingContext ctx)

{

//zawsze zapisuj dużymi literami

info.AddValue("First_Item", dataItemOne.ToUpper());

info.AddValue("dataItemTwo", dataItemTwo.ToUpper());

}

}

164

Page 165: C#, Visual Studio 2010, .NET 4.0

Iserializable c.d.Iserializable c.d.static void Main(string[] args)

{

StringData myData = new StringData();

SoapFormatter soapFormat = new SoapFormatter();

using(Stream fStream = new FileStream("MyData.soap", FileMode.Create, FileAccess.Write, FileShare.None))

{

soapFormat.Serialize(fStream, myData);

}

Console.ReadLine();

}

165

Page 166: C#, Visual Studio 2010, .NET 4.0

Albo poprzez atrybuty (bez Albo poprzez atrybuty (bez dziedziczenia z Iserializable):dziedziczenia z Iserializable):[Serializable]

class MoreData

{

private string dataItemOne = "First data block";

private string dataItemTwo= "More data";

[OnSerializing]

private void OnSerializing(StreamingContext context)

{

// Called during the serialization process.

dataItemOne = dataItemOne.ToUpper();

dataItemTwo = dataItemTwo.ToUpper();

}

[OnDeserialized]

private void OnDeserialized(StreamingContext context)

{

// Called once the deserialization process is complete.

dataItemOne = dataItemOne.ToLower();

dataItemTwo = dataItemTwo.ToLower();

}

}166