You are on page 1of 143

C#

Guide étape par étape pour les débutants en


programmation C#
© Copyright 2017 – Tous droits réservés

Si vous souhaitez partager ce livre avec une autre personne, veuillez en


acheter une copie supplémentaire pour chaque destinataire. Merci de
respecter le travail acharné de cet auteur. Dans le cas contraire, la
transmission, la duplication ou la reproduction de l'un ou l'autre des travaux
suivants, y compris des renseignements spécifiques, seront considérés
comme un acte illégal, qu'ils soient effectués par voie électronique ou écrit.
Cela s'applique à la création d'une copie secondaire ou tertiaire de l'œuvre
ou d'une copie enregistrée qui n'est autorisée qu'avec le consentement écrit
exprès de l'éditeur. Tout droit supplémentaire réservé.
Sommaire

Chapitre
1………………………………………………………………………………
…... 7
Installation et introduction
………………………………………………………………….7
Histoire de C#
……………………………………………………………………………….
7
Pourquoi C#
….……………………………………………………………………………
…7
Lancer C# sur
Windows..……………………………………………………………………
7

Chapitre
2………………………………………………………………………………
…….9
Classes et programmation des objets
connectés…………………………………………...12
Classes
basiques………………………………………………………………………
……12
Propriétés..…………….……………………………………………………
……………..14
Constructors et
destructors ………………………………………………………………..19
Héritage………………………………………………………………………
……………….24
Résumé………………………………………………………………………
……………….25
Quiz de fin de
chapitres……………………………………………………………………
…27
Réponses……………………………………………………………………
………………..28

Chapitre
3………………………………………………………………………………
…..29
Structures de classes
avancées…………………………………………………………….29
Polymorphisme…
…………………………………………………………………………..29
Interfaces……………………………………………………………………
………………35
Exercices
………………………………………………………………………………
……37
Quiz de fin de
chapitre………………………………………………………………………
41
Réponses……………………………………………………………………
……………….41
Chapitre 4
………………………………………………………………………………
…43
Fonctionnalité
intermédiaire……………………………………………………………. 43
Exercice………………………………………………………………………
…………….44
Expression régulière
………………………………………………………………………46
Directive du pré-
processeur….…………………………………………………………….52
Gestions des
exceptions….………………………………………………………………..5
5
Questions de fin de
chapitre………………………………………………………………59
Réponses….…………………………………………………………………
……………59

Chapitre 5
………………………………………………………………………………
…60
Programme
formateur……………………………………………………………………
60
Caractéristiques
……………………………………………………………………………60
Réflexion……………………………………………………………………
……………...65
Métadata… …………………………………………………………………
……………..65
Indexeurs
………………………………………………………………………………
….67
Collection……………………………………………………………………
…………..72
Génériques…………………………………………………………………
…………….75
Question de fin de
chapitre………………………………………………………………79
Réponses……………………………………………………………………
……………79
Chapitre
6………………………………………………………………………………
..79
Processus et
fonctionnalités……………………………………………………………..8
0
Déléguées.
………………………………………………………………………………..
80
Méthodes
anonymes…………………………………………………………………….
..84
Evénements…………………………………………………………………
……………86
Multithreading………………………………………………………………
……………88
LINQ…………………………………………………………………………
…………..95
Exercices….…………………………………………………………………
…………..97
Questions de fin de
chapitre……………………………………………………………..99
Réponses
….…………………………………………………………………………….
.99
Chapitre 1

Installation et introduction

Histoire de C#

La première version de C# est apparue en 2000 lorsqu’elle a été annoncée


par Microsoft, C# est un la langage Microsoft appartenant à la famille des
C. Il a été crée par une équipe dirigée par Anders Hejlsberg. Initialement le
nom proposé pour ce langage était « Cool » signifiant « C-Like Object
Orientated Language » , Microsoft décida finalement de l’appeler C#. Le
symbole dièse est utilisé mais prononcé « sharp », cela a été fait exprès car
il y a beaucoup de claviers où il n’y avait pas le symbole dièse à l’époque.
Le symbole dièse ressemble également à quatre symboles + dans une grille
de 2 sur 2, impliquant fortement que C# est une augmentation ultérieure de
son langage frère C ++.

En dessous vous trouverez une ligne de temps du langage C# et ce


qu’inclut chaque amélioration ajouté ou modernisé (toutes les propriétés
seront expliqués plus tard dans le guide)

Jan 2002
C# 1.0
-Type safe programming language
-Modern
- OOP (Object Orientated Programming)
Nov 2005
C# 2005
-Generics
-Partial classes
-Anonymous types
-Iterators
-Nullable types
-Static classes
Nov 2007
C# 2007
-Improvements of previous additions
-Extensions methods
-Expression trees
-Partial methods

April 2010
C# 4.0
-Dynamic binding
-Naming and optional arguments

Aug 2012
C# 5.0
-Asynchronous Programming
A huge addition allowing programmers to create multithreaded
applications
-Caller info attributes

July 2015
C# 6.0 (Version in this tutorial)

-Exception filters
-String interpolation
-Static type members into namespaces
-Complier as a service

Pourquoi C# ?
C# possède beaucoup d’avantages par rapport aux autres langages
similaires comme Java ou Python.
C # est un type incroyablement sûr, ce qui signifie que lorsqu'une
variable est créée, un type doit être défini, ce qui signifie qu'un
autre type ne peut pas être logé dans cette variable.
C# possède un contrôle totale sur les fuites de mémoire qui sont
une grande inquiétude pour beaucoup de programmeurs C++
C# fournit une librairies riche de propriétés ce qui permet
d’implanter des propriétés en plus simple et directe.
N’importe quel système avec .NET framework lancera
l’application. Cependant, le cadre est supporté principalement sur
Windows, ce qui signifie que les supports Linux ou Mac sont
presque ou entièrement non-existants

Lancer C# sur Wundows

Lancer C# selon moi est le meilleur moyen et presque le seul moyen


de coder et travailler avec C#, c’est un langage crée par Microsoft et
ils ont fait tout ce qu’ils ont pu pour rendre facile le travail sur une
machine Windows, même si cela signifie ignorer les autres
plateformes entièrement.

Utilisateurs de Mac :

Récemment il y a eu une date de sortie pour Visual Studio pour Mac,


mais c’est rudimentaire et ne possède pas les propriétés que Windows
Visual Studio a, il est donc fortement conseillé de travailler avec C #
sur une machine Windows. Mais il a plusieurs moyens d’avoir
Windows OS pour le lancer sur Mac, chercher « Virtual Box » par
Oracle, c’est un programme qui vous permet de faire fonctionner une
machine Windows virtual.

Pour travailler avec C#, vous auriez besoin de télécharger Visual


Studio, qui peut être télécharger directement depuis Microsoft. S’il
vous plait lancer l’installer et installer Visual Studio.
Lorsque vous avez complété l’installation entièrement vous serez
accueilli sur cet «écran ».

Cliquez sur File et sélectionnez « Nouveau Projet »

Vous obtiendrez l’écran ci-dessous, sélectionnez ConsoleApplication et


donnez lui un nom
Cliquez sur « Ok ». Ensuite nous vous présenterons quelques codes
où vous pourrez commencer à programmer.
Chapitre 2

Classes and Object Orientated Programming

Classes basiques

Les classes sont utilisés pour enregistrer les variables et les


fonctionnalités pertinentes à un objet, par exemple il y a une classe
créée pour un « Book », il y aurait des informations tel que le nombre
de pages, le genre la couleur de la couverture et des fonctionnalités
comme «livre de prêt» ou «livre de retour». C'est de là que vient toute
la nature liée au monde réel et utile avec les classes, et le mot objet
dans la OOP.

Avant que nous rentrions dans le sujet de comment créer un classe, il


y a des mots clés accessor qui ont besoin d’être compris :
Private ne peut être accédé en dehors de la portée de la
classe
Publique peut être consulté de n’importe ou
Protégé peut être consulté des classes hérités

Vous définirez une classe comme ci dessous


class Book
{

}
Avec toutes ces variables et fonctions définis dans les parenthèses, une
version étoffée ci dessous

class Book
{
public Book(int numberOfPages, int currentPage, string colour, string
name)
{
_numberOfPages = numberOfPages;
_currentPage = currentPage;
_colour = colour;
_name = name;
}

private int _numberOfPages;


private int _currentPage;
private string _colour;
private string _name;

public string changeMe;

public int returnCurrentPage()


{
return _currentPage;
}

}
Il y a plusieurs choses à noter. Les fonctions dans la boite sont connues
come Constructors (expliqué dans ce chapitre), il est appelé lors de la
création d’un nouvel objet. Cette classe contient toutes les variables et les
fonctions membres, qui sont tous les deux accessibles en utilisant
l'opérateur membre. Dans ce cas toutes les variables sont marqués comme
« privé » , signifiant qu’on ne peut y accéder en dehors de la classe, c’est là
que getters et setters ( Acessors methods) entrent en usage, la fonction
« returnCurrentPage » est une getter ? et vous permet d’accéder à la valeur
de la page en cour , c'est la manière recommandée de gérer l'accès aux
variables, cela permet au programmeur de contrôler l'accès aux variables.

Un objet est crée juste en dessous, avec quelques fonctions et variables


permettant l’accès :

class Program
{
static void Main(string[] args)
{
Book book1 = new Book(200, 32, "Red", "Harry Potter");

book1.changeMe = "Test";
Console.WriteLine(book1.changeMe);

int currentPage = book1.returnCurrentPage();


Console.WriteLine(currentPage);
}
}
Output
>Test
>32

Recap :
Les classes fournissent une manière intuitive de stocker les
données sur des objets du monde réels.
Ils permettent de construire des fonctionnalités autour des
données.
Elles sont utilisées comme une façon de faire des tas de
conteneurs pour les données.
Accesor methods permette l’accès pour modifier la valeur.

Propriétés :

Comme mentionné dans le chapitre précèdent ou les propriétés de


l’Accessor methods permettent un solution lisible simple pour accéder aux
membres variables en une petite syntaxe compactée. Les propriétés
contiennentt aussi les définitions des variables. Elles sont définies ainsi :

public int currentPage


{
get
{
return currentPage;
}
set
{
currentPage = value;
}
}

Et appelé ainsi :

Book book1 = new Book();

book1.currentPage = 2; //2 is ‘value’ in the set


Console.WriteLine(book1.currentPage);

Cela accompli exactement le même rôle que l’accessor dans le chapitre


précèdent mais avec une syntaxe beaucoup plus précise en comparaison :

private int _currentPage;


public int returnCurrentPage()
{
return _currentPage;
}

Cela revient à :

public int currentPage { get; }


Comme vous pouvez le voir, c ‘est un code beaucoup plus petit.

Une utilisation plus avancée de setter pourrait être de valider l’input ?. Par
exemple, vous ne pouvez pas avoir la page en cours qui est plus large que le
nombre total de pages. Le code ressemble donc à cela :

class Book
{
int totalPages = 500;
public int currentPage
{
get
{
return currentPage;
}
set
{
//Validation check
if (value < totalPages)
{
currentPage = value;
}
else if(value == totalPages)
{
Console.WriteLine("You've finished the book!");
}
else
{
//Error message
Console.WriteLine("Invalid current page!");
}
}
}

}
Cela donne au programmeur la possibilité d'écrire du code qui tient compte
de nombreuses possibilités.
Static :
Comme mentionné dans le chapitre précédent, les fonctions membres
permettent aux classes de contenir les fonctionnalités qui sont en quelques
sorte relié aux données contenus dedans, ce qui permet aux classes d’être
presque des programmes autonomes avec les membres variables qui
donnent aux classes leur fonctionnalité.

Les fonctions et variables membres sont d »finis comme « static », ce qui


signifie que l’objet est « toujours là ». Ceci est utilisé lorsque le
comportement ne changera pas toutes les instances de la classe et de plus
cela signifie que le comportement ou le comportement ou la variable est
partagée entre eux tous.

Note: les fonctions statiques ne peuvent accéder seulement qu’à des


variables statiques
using System;

namespace ConsoleApplication1
{
//
class Program
{
static void Main(string[] args)
{
Example e = new Example();
e.Instance();
e.Static() //Error

Example.Instance(); //Error
Example.Static();
}
}

class Example
{
public void Instance()
{
Console.WriteLine("Instance!");
}
public static void Static()
{
Console.WriteLine("Static!");
}
}
}

Cet exemple ci dessus montre comment les différents types de fonctions


peuvent être accéder et gérer.
Ci dessous un exemple de travail statique avec un exemple « réel »
using System;

namespace ConsoleApplication1
{
//
class Program
{
static void Main(string[] args)
{
int i = Person.WorkOutAge(new DateTime(1990, 10, 15));
Console.WriteLine(i);
}
}

class Person
{
public Person(string _name, int _age)
{
name = _name;
age = _age;
}

public string name { get; }


public int age { get; }

public static int WorkOutAge(DateTime birthday)


{
//Time since
TimeSpan difference = DateTime.Now - birthday;

double years = difference.TotalDays / 365;

return (int)years;
}
}
}
Ce programme utilise une méthode statique pour calculer l’âge d’une
personne en utilisant leur date de naissance, ce qui permet à la méthode de
contenir des fonctions révélatrices sans en séparée une crée par instance.

Connectors et Destructors :

Lorsque vous créez une classe en instance un constructor est utilisé, le


langage fournit un constructor par défaut, mais un constructor customisé
peut-être crée, vous avez peut-être vu les fonctions sans retour et avec
exactement le même nom de classe, pour continuer avec notre classe de
personne par exemple :

class Person
{
public Person()
{
Console.WriteLine("Person created");

}
}

Ceci est un constructor customisé qui imprime juste lorsqu’une Personne


est crée. Normalement les construtors sont utilisés pour passer les données
aux membres variables lorsqu’une instance de la classe est crée.

Vous pouvez aussi avoir autant de constructors que vous voulez, cependant
ils ont tous besoin de différents types de paramètres et de nombres de
paramètres (ceci est connu comme une fonction signature) donc avec les
exemples ci dessous je ne pourrais pas définir d’autre constructors sans
paramètres, ceci est connu comme une surcharge (= overloading).

Par exemple :
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Person p1 = new Person("John", 32);
Person p2 = new Person("James", 50, "Train Driver");
}
}

class Person
{
public Person(string _name, int _age)
{
name = _name;
age = _age;
job = "N/A";
}
public Person(string _name, int _age, string _job)
{
name = _name;
age = _age;
job = _job;
}

public string name { get; }


public int age { get; }
public string job { get; }

}
}
La section surlignée montre l’utilisation de la surcharge, le compiler détecte
automatiquement quel constructor utiliser en fonction des types dans la liste
de paramètres.

Comme il y a un constructor il y a un destructor qui effectue le rôle opposé


du constructor qui au lieu de gérer les créations de codes the les destructors
s’occupent des codes de nettoyage.

Un destructor est crée comme ceci :

class Person
{
~Person()
{
Console.WriteLine("Person deleted!");
}
}

Cette méthode ne peut être appelée manuellement mais est gérée par
l’interne Garbage Collector qui est construit en partie par le compiler crée
par le management de mémoire automatique.

Cela peut être démontré ainsi, si la méthode est appelée et qu’il crée une
instance à la Personne et qu’ensuite le programme sort de la portée de la
méthode principale, le garbage collector sera appelé pour nettoyer la
mémoire.
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Function();

static void Function()


{
Person p1 = new Person();
}
}

class Person
{
~Person()
{
Console.WriteLine("Person deleted!");
Console.ReadKey();
}
}
}
Output
>Person deleted!

Exercice :

Créez une classe qui contient les données pour Pets, la classe aura besoin
d’un nom, un âge et un type d’animal. Il y aura aussi besoin d’un
Cosntructor d’un destructor et d’un membre fonction qui imprime toutes les
données pour l’animal.

Le tester en ayant un chien appelé Jose qui a un 1 an, un chat appelé Besse
qui a cinq ans et un perroquet appelé James qui a 10 ans.

Solution :

Cela devrait ressembler à quelque chose comme cela

using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Pet p1 = new Pet("Jose", 1, "Dog");
p1.Print();

Pet p2 = new Pet("Besse", 5, "Cat");


p2.Print();

Pet p3 = new Pet("James", 10, "Parrot");


p3.Print();

Console.ReadKey();
}
}

class Pet
{
public Pet(string _name, int _age, string _type)
{
name = _name;
age = _age;
type = _type;
}

string name { get; }


int age { get; }
string type { get; }

public void Print()


{
//{name} is string interpolation
Console.WriteLine($"Name: {name}",name);
Console.WriteLine($"Age: {age}",age);
Console.WriteLine($"Type: {type}",type);
Console.WriteLine();
}
}
}

Héritage :

L’héritage est une fonction de langage qui permet aux classes de prendre en
compte les caractéristiques d’un autre, l’héritage est fait de cette façon :

class Dog : Animal


{

Ce qui signifie que n’importe quel fonction ou variable est marquée comme
« Publique » ou « Protégé » (protégé est expliqué dans le chapitre suivant).
Le chien aura sa propre version pour y accéder, ce qui permet de créer
rapidement de nouveaux types de classes sans répéter la fonction et la
définition des variables.

L’exemple ci dessous montre comment cela peut être utilisé :

using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Dog d1 = new Dog("Rocko", 3, "Blue One", "Red");

d1.PrintName();
}
}

class Animal
{
public Animal(string _name, int _age)
{
name = _name;
age = _age;
}

public string name;


public int age;

public void PrintName()


{
Console.WriteLine(name);
}
}
class Dog : Animal
{
public Dog(string _name, int _age, string favBone, string kColour) :
base(_name, _age)
{
FavouriteBone = favBone;
kColour = KennelColour;
}

private string FavouriteBone;


private string KennelColour;
}
}

Il y a quelques points à mentionner, d’abord l’exemple ci dessus montre


comment les fonctions sont hérités, le chien n’a pas la définition
« PrintName » car il hérite « Animal » qui a sa propre définition.

Le second point est que « base(__name,__age) » c’est ainsi que vous


nommé le constructeur de base, dans ce cas il s’appelle l’Animal
constructor.

L’encapsulation :

L’encapsulation est le processus d'inclusion d'un ou de plusieurs éléments


dans un package physique ou logique et dans le contexte de la POO est la
manière dont l'accès aux variables membres est géré.

Nous en avons vu trois auparavant mais dans cette section, nous irons plus
dans les détails à propos des sections ci dessous :
Publique
Protégée
Privé
Interne
Protection interne

Publique :
Publique vous permet simplement un accès total à tout les objets membres.

Par exemple :

class Program
{
static void Main(string[] args)
{
Public p = new Public();

//value can be accessed and changed no problem


p.value = 3;
}
}

class Public
{
public int value;
}

Privée :
C’est l’opposé complet de publique ou les appels internes à une variable
sont autorisés, ce qui signifie qui si nous voulons changer une variable nous
devons utiliser la fonction accesor
class Program
{
static void Main(string[] args)
{
Private p = new Private();

//Error here!
p.value = 3;
}
}

class Private
{
private int value;
}

Protégé :

Protégé est un petit peu différent, cela implique l’héritage lorsqu’une classe
hérite des fonctions et des variables d’un autre mentionné précédemment.
Interne :

Ceci permet à la classe d’exposer les deux fonctions et variables à un objet


dans l’assemblage actuel, essentiellement c’est juste n’importe quel
fonction contenue dans l’application.

Protection interne :

La protection interne ressemble beaucoup à l’interne mais avec quelques


différences, cela implique l’héritage presque comme protégé.

Note :
Vous pensez peut-être et si un modificateur d'accès n'est pas spécifié? Et
bien dans ce cas (et c’est totalement valide), par défaut cela sera privé.

Question de fin de chapitre :

1 . Que signifie OOP ?


2. Quels sont les fonctions appelées qui permettent de passer en privé les
variables membres ?
3. Expliquez le rôle d’une propriété ?
4. Définir une classe de variable membre comme « statique » achève quoi ?
5. Qu’est une fonction statique accède ?
6. Comment le destructor est appelé par le programmer ?
7. Quelle section du complier gère automatiquement avec le management
de mémoire ?
8. Ou pouvez accéder à une variable marqué comme interne ?
9. Quel est le nom technique pour une nouvelle version de classe crée ?
10. Quel est le nom pour l’utilisation de multiples constructors ?

Réponses

1. Programmation d’objet orienté


2. Getters (fonction accesor)
3. Un syntaxe plus petite et concise pour les getter, setters et les
définitions de variables.
4. Ce qui signifie que la présence de variable est constante entre
chaque instance de classe.
5. Variables statiques
6. Ce n’est pas, le destructor ne peut être appelé manuellement
7. Le garbage collector
8. Dans la même assemblé, i.e dans le même dossier exe ou .dll
9. Une instance de classe
10. Une surcharge de classe
Chapitre 3

Structures de classes avancées

Polymorphisme

Le mot polymorphisme signifie avoir plusieurs formes, dans le contexte


OOP cela est souvent décrit comme « une interface, plusieurs fonctions »
Il y a deux types de design polymorphiques, statique et dynamique
polymorphisme.

Statique polymorphisme

Le statique polymorphisme est la réponse à une fonction qui est déterminée


à un temps compilé ( i.e. avant que le programme ne soit lancé) ce procédé
est appelé « Early binding » et cela peut être exécuter de deux manières
différentes.
Fonction overloading
Opérateur overloading

Fonction overloading

Dans la fonction overloading vous avez la même définition d’une fonction


dans le même cadre, c’est exactement la même chose que les constructor
overloading

Donc par exemple la définition de classe serait valide pour :


using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Interface i = new Interface();

//Printing integer
i.Print(1);

//Printing float
i.Print(2.0f);

//Printing double
i.Print(4d);

//Printing long
i.Print(4L);
}
}

class Interface
{
string printStr = "Print!";
public void Print(int i)
{
Console.WriteLine(i);
}

public void Print(double i)


{
Console.WriteLine(i);
}

public void Print(float i)


{
Console.WriteLine(i);
}

public void Print(long i)


{
Console.WriteLine(i);
}
}
}

Comme vous pouvez le voir il y a quatre définitions de « Print() » mais


toutes avec des paramètres différents.

Dynamique overloading :
C# permet la création d’une classe abstraite ; une classe abstraite peut agir
comme un modèle ou un design pour d’autres classes pour hériter et
s’adapter pour les circonstances pour lesquelles elles sont crées. Ensuite les
classes dérivées peuvent prendre des fonctions abstraites et adapter leurs
comportements, cependant il y a des règles à propos des classes abstraites :
Vous ne pouvez pas créer directement une instance d’une classe
abstraite
Vous ne pouvez pas déclarer une méthode abstraite qui n’est pas
logé dans une classe abstraite
Il y a aussi un mot clé connu comme « sealed » et les classes
scellées ne peuvent être hérité, par conséquent les méthodes
abstraites ne peuvent être définis comme scellées.
Ci dessous un exemple qui montre l’utilisation d’une classe abstraite :

using System;
namespace ConsoleApplication1
{
abstract class Shape
{
public abstract int Volume();

public int height { get; set; }


public int width { get; set; }
}

//Creates a 2D Rectangle
class Rectangle : Shape
{
public Rectangle(int w, int h)
{
height = h;
width = w;
}

public override int Volume()


{
return height * width;
}
}

//Creates a 3D Cylinder
class Cylinder : Shape
{
public Cylinder(int w, int h)
{
height = h;
width = w;
}

public override int Volume()


{
//(π * (width / 2)^3) * height
return (int)(Math.PI * Math.Pow(width / 2, 3)) * height;
}
}

class Program
{
static void Main(string[] args)
{
Rectangle rec = new Rectangle(10, 10);
Console.WriteLine(rec.Volume());

Cylinder cylin = new Cylinder(10, 10);


Console.WriteLine(cylin.Volume());

Console.ReadKey();
}
}

Quelques petites choses à noter dans cette partie entourée par le rectangle
est la définition de la classe abstraite, ou un volume de classe abstraite est
défini, ceci est ensuite pris dans les autres méthodes et est surchargé,
remarqué que le mot-clé « surcharge » qui est utilisé pour créer une
définition customisé du Volume() où chaque classe possède une conception
customisée par Volume appelé qui est ensuite appelé dans la méthode
principale. Une classe abstraite requiert que la méthode qui hérite doit créer
une version surchargée. Ce qui signifie que les classes abstraites sont
conçues pour être des plans très stricts pour la forme et la disposition d'une
méthode.

Il y a aussi un autre type de surcharge dynamique, connu comme « Virtuel »


très similaire à l’abstrait mais c’est une version optionnelle ou la définition
est :
La classe de base peut être optionnellement remplacé, en dessous voici un
exemple :

using System;
namespace ConsoleApplication1
{
class Human
{
public virtual void SayHello()
{
Console.WriteLine("Hello!");
}
}

class American : Human


{
//No override needed as SayHello is valid
}

class Columbian : Human


{
public override void SayHello()
{
Console.WriteLine("Hola!");
}
}

class French : Human


{
public override void SayHello()
{
Console.WriteLine("Bonjour!");
}
}

class Program
{
static void Main(string[] args)
{
American a = new American();
a.SayHello();

Columbian c = new Columbian();


c.SayHello();

French f = new French();


f.SayHello();

Console.ReadKey();
}
}
}

Comme vous pouvez le voir chaque classe hérite de la classe humaine et


quelques autres remplacent les classes virtuelles mais certaines comme la
classe Américaine n’ont pas besoin d’être remplacé, ce qui donne l’option
de changer la classe si besoin est.

Interfaces

Les interfaces sont très structurées, ils sont une copie bleue que chaque
méthode héritée doit suivre, un peu comme un contrat. Une interface est un
peu comme une classe abstraite mais comment une classe abstraire peut
hériter et être étendu alors qu’une interface doit juste être implanté. Les
interfaces permettent la séparation des définitions de fonctions depuis
l’implantation et améliorer la lisibilité et le design.
Une interface est définie comme chaque méthode ou propriété qui doit être
créer est poser dans une sorte de liste, une interface ne peut pas contenir
d’implémentation.

interface ITransaction
{
//Methods
void Process();
}

Ci dessous un exemple en utilisant une interface avec l’exemple utilisé


impliquant les véhicules.

interface IVehicle
{
string Colour { get; }
string EngineType { get; }
int NumberOfWheels { get; }
int Gas { get; }

void StartEngine();
void StopEngine();
}

class Car : IVehicle


{
public string Colour { get; }
public string EngineType { get; }
public int NumberOfWheels { get; } = 4;
public int Gas { get; }

public void StartEngine()


{
Console.WriteLine("Started Engine!");
}

public void StopEngine()


{
Console.WriteLine("Stopped Engine!");
}

public Car(string colour, string engineType, int gas)


{
Colour = colour;
EngineType = engineType;
Gas = gas;
}
}

Comme vous pouvez le voir, « Car » doit implanter tous les items définis
dans l’interface IVehicle, ce qui donne une sorte de « plug and play » effet
lorsque vous créez de nouvelles classes qui concernent les véhicules car le
design et layout est très renforcé.

Exercice :

En utilisant l’exemple précédent implanté une nouvelle classe appelé Bike


en utilisant l’IVehicles interface, pour comprendre comment l’interface
fonctionne

Solution

L’implantation de la classe devrait ressembler à cela :

class Bike : IVehicle


{
public string Colour { get; }
public string EngineType { get; }
public int NumberOfWheels { get; } = 2;
public int Gas { get; }

public void StartEngine()


{
Console.WriteLine("Started Engine!");
}

public void StopEngine()


{
Console.WriteLine("Stopped Engine!");
}

public Bike(string colour, string engineType, int gas)


{
Colour = colour;
EngineType = engineType;
Gas = gas;
}
}

Namespaces :

Les namespaces sont utilisés pour séparer les définitions, cela fait que les
noms définis dans un espace de noms ne sont pas en conflit avec un autre.

Un namespace est définis ainsi :


namespace Namespace1
{

}
Et pour appeler une autre fonction de namespace vous devez utiliser les
membres opérateurs de cette manière :

Namespace1.Class c = new Namespace1.Class();

Note : namespace ne peut contenir directement les définitions des fonctions


ou des variables

Ci dessous un exemple utilisant un autre namespace :

using System;
namespace ConsoleApplication1
{
class Program
{
public class SameName
{
public void Function()
{
Console.WriteLine("Main!");
}
}

static void Main(string[] args)


{
SameName s1 = new SameName();
s1.Function();
Namespace1.SameName s2 = new Namespace1.SameName();
s2.Function();

Console.ReadKey();
}
}
}

namespace Namespace1
{
public class SameName
{
public void Function()
{
Console.WriteLine("Namespace1!");
}
}
}

Output
>Main!
>Namespace1!

Noter qu’ici il y a deux classes avec une classe « samename » et comment


vous spécifiiez laquelle avec le Namespace et le membre.
Namespace dans les autres dossiers ou dans celui la peut être
automatiquement spécifié en utilisant le mot clé, vous avez peut-être
remarqué :

using System;

Cela est apparu sur le dessus de certains extraits de code, c’est simplement
le programme qui vous indique d’utiliser le « System » namespace pour des
items comme

Console.WriteLine("");

Et

Console.ReadKey();

L’utilisation peut-être aussi coupé du précédent namespace spécifié.

Sans utiliser la déclaration :

using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Namespace1.Class c = new Namespace1.Class();
c.Function();

Console.ReadKey();
}
}
}

namespace Namespace1
{
public class Class
{
public void Function()
{
Console.WriteLine("Namespace1!");
}
}
}

En utilisant le segment : b

using System;
using Namespace1;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Class c = new Class();
c.Function();

Console.ReadKey();
}
}
}

namespace Namespace1
{
public class Class
{
public void Function()
{
Console.WriteLine("Namespace1!");
}
}
}

Remarquez comment les références de classe sont maintenant plus courtes


et plus agréable à lire.

Quiz de fin de chapitre

1. Quelles sont les deux façons d’implanter le Polymorphisme ?


2. Qu’est ce qui est appelé lorsqu’il y a plus d’une version d’un
contractor ou d’une fonction ?
3. Définissez une classe comme sealed achieves what ?
4. Qu’est ce que vous ne pouvez pas faire avec une classe
abstraite ?
5. Quel mot clé est utilisé lorsque vous implantez une méthode
virtuelle ou abstraite
6. Les namespaces sont utilisés dans quel but ?
7. Pouvez vous créer une méthode abstraite qui n’est pas logée dans
une classe abstraite ?
8. Quelle est la principale différence entre une interface et une
classe abstraite ?
9. Quel opérateur utilisez vous lorsque vous accéder aux items du
namespace ?
10. Comment pouvez vous dire que le compiler inclus d’autres
namespaces automatiquement ?

Réponses :

1. Statique et dynamique polymorphisme


2. Surcharge
3. Signifie que la classe ne peut être hérité
4. Créer directement une instance
5. Surcharge
6. Séparer les noms des classes et méthodes
7. Non, toutes les méthodes abstraites ont besoin d’être dans une
classe abstraite
8. Les interfaces ne permettent pas aux implantations d’être
ajouté et sont des plans blues pour créer de nouvelles classes.
9. Le membre opérateur (full stop)
10. En ajoutant une déclaration « utilisant » au début du
programme.
Chapitre 4

Fonctionnalité intermédiaire

Opérateur overloading

C# possède un support pour altérer la fonctionnalité de beaucoup built-in


opérateurs comme « + « ou le membre opérateur « . » que nous avons
croisé précédemment. Les surcharges operateurs possèdent des fonctions
spéciales qui incluent le mot clé « opérator » suivi du signe opérateur,
exactement comme n’importe quel fonction d’opérateurs overloaded qui ont
un type de retour et de liste de paramètre.

Dans cet exemple nous allons créer une classe appelé « Grade » et
surchargé le plus opérateur. Un opérateur overloader est défini comme :

public static Grade operator+(Grade a, Grade b)


{
}

Note : cette fonction d’opérateur a besoin d’être statique et publique.

Cet exemple ci dessous implante l’overload operator

using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Grade a = new Grade(30);
a.Print();

Grade b = new Grade(40);


b.Print();

Grade c = a + b;
c.Print();

Console.ReadKey();
}
}

class Grade
{
int mark;

public Grade(int m)
{
mark = m;
}

public void Print()


{
Console.WriteLine($"The mark is: {mark}", mark);
}

public static Grade operator+(Grade a, Grade b)


{
Grade c = new Grade(0);
c.mark = a.mark + b.mark;
return c;
}
}
}

Output
>The mark is: 30
>The mark is: 40
>The mark is: 70

Dans cette instance l’opérateur prend juste la marque de chaque grade


instance et ajoute le résultat. Ceci est un exemple très basique et la
surcharge de l'opérateur peut être incroyablement utile.

Exercice :

Par exemple si nous voulions comparer les deux grades à ce moment si


nous ajoutions :

if (a == b)
{
Console.WriteLine("Equal grades!");
}
Et définissez les deux notes comme étant exactement les mêmes, disons 30.
Il faut imprimer "Grades égaux"

Surcharge le « == » opérateur compare les deux notes et voit si elles sont


égales

Note :
La fonction surcharge opérateur doit retourner un bool
Le « != » operateur a aussi besoin d’implanter à ces cotés ( cela
fera juste l’opposé complet)

Solution

Le programme entier devrait ressembler à cet exemple, les nouvelles


additions sont entourés par les boites :

using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Grade a = new Grade(30);
a.Print();
Grade b = new Grade(30);
b.Print();

//Test
if (a == b)
{
Console.WriteLine("Equal grades!");
}

Console.ReadKey();
}
}

class Grade
{
int mark;

public Grade(int m)
{
mark = m;
}

public void Print()


{
Console.WriteLine($"The mark is: {mark}", mark);
}
public static Grade operator+(Grade a, Grade b)
{
Grade c = new Grade(0);
c.mark = a.mark + b.mark;
return c;
}

public static bool operator==(Grade a, Grade b)


{
return a.mark == b.mark;
}
public static bool operator !=(Grade a, Grade b)
{
return a.mark != b.mark;
}
}
}

Output
>The mark is: 30
>The mark is: 30
>Equal grades!

Expression régulière

Les expressions régulières sont une manière de faire correspondre des


modèles dans un texte inputted, le .NET cadre de travail doit construire un
support d’expression régulière.
Cela sera un aperçu de comment utiliser les expressions basiques, il y a
beaucoup de combinaisons à apprendre et faire quelques recherches après
ce chapitre est conseillé.

Chaque expression régulière a besoin d’être construite, ci dessous une liste


de chaque caractère, operateur et fonction qui vous permet de créer une
expression régulière

Anchors & Extras

Character Description
^ Est une référence pour commencer
le mot
$ Réfère à la fin d’une ligne
\w Réfère à un mot consistant de a-
z,A-Z,0-9 et souligner
+ Réfère à 0 ou à plus de récurrences
| Utilisé pour spécifier « ou »
[nnn] Utilisé pour spécifier une classe de
caractère pour vérifier avec
i.e(abcd) ne retournera que les
matchs sur aabc et pas dcab

Donc par exemple le regex

^\w+$
Cela semble intimidant je sais, mais cela correspond simplement à
n’importe quel mot donné en utilisant le System.Text.Regular.Expression
nous pouvons faire correspondre un motif. Le code ci dessous le démontre :

using System;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
while (true)
{
//Change expression here!
string regExpression = @"^\w+$";

Console.WriteLine("Please input text");


string input = Console.ReadLine();

if (Regex.IsMatch(input, regExpression))
{
Console.WriteLine($"{input} is a match!", input);
}
else
{
Console.WriteLine("No match!");
}

Console.WriteLine();
}

}
}
}

Copier ce programme à un projet Visual Studio et lancer le, essayer


différentes sorties. Tout ce qui inclut juste A-Z,a-z,0-9 et un score en
dessous correspondra, mais les espaces et ponctuations par exemple ne
retournera pas de match.
Notez que l’utilisation du signe « @ » est placé avant une ligne qui veut sa
valeur soit prise littéralement, i.e. désactivez la barre oblique inverse pour
spécifier les caractères spéciaux.

Un autre exemple complexe est :

^([\w]+\.[\w]+)$

Cette section dans les parenthèses spécifie le set de caractère, donc dans
cette case cela dit que n’importe quel mot avec (A-Z,a-z,0-9 et ‘_ ») est
valide ensuite il va dans “\.”qui vérifient un arrêt entier et le [\ w] + est
répété après l'arrêt, donc cette regex cherche un motif d'un mot séparé par
un arrêt complet. Ajoutez cette expression au programme utilisé dans
l'exemple précédent et essayez-le.

Cela peut maintenant être adapté à ce complex regex utlisé pour identifier
des adresses email , chaque section sera expliqué

^((([\w]+\.[\w]+))|([\w]+))\@([\w]+\.)+([A-Za-z]{1,2}\.([A-Za-z]{1,2})|
([A-Za-z]{1,3}))$

Le regex identifiera maintenant les adresses email :


(([\w]+\.[\w]+)|[\w]+))
Est égal à n’importe quel nombre de caractères divisés
avec a « . » suivi par n’importe quel nombre de
caractères standards
OR (|)
N’importe quel nombre de caractères standard
\@([\w]+\.)+
\@ correspondra à un signe “@”
Suivi d’un nombre de caractères
Suivi d’un arrêt total
+ signifie n’importe quel nombre d’items dans les
parenthèses
([A-Za-z]{1,2}\.([A-Za-z]{1,2})|([A-Za-z]{1,3}))
[A-Za-z] spécifie qu’un mot fait de upper et lower
cases lettres, le “{1,2}” spécifie la longueur du mot ,
d’un minimum de et d’un maximum de deux caractères
\. Séparé par un ‘.’
Un autre “[A-Za-z]{1,2}”
OR (|)
“[A-Za-z]{1,3}” – comme “[A-Za-z]{1,2}” mais avec
une largeur plus importante

Les espaces de caractères :


Dans une expression régulière, le signe backslash “\” signifie que le
caractère ou le groupe de caractères suivant sont spéciaux ou à prendre
littéralement
Caractère Description Nombre unicode (hex)
\t Correspondra à un 0009
caractère de tabulation
\r Va correspondre à un 000D
retour chariot (Notez
que ce n'est pas la
même chose qu'un saut
de ligne (\ n)
\f Correspond à un flux 000C
de formulaire (mieux
connu sous le nom de
saut de page
\n Correspond à une 000A
nouvelle ligne
\e Correspond à échap 001B
\nnn Utilise la Chaque lettre a son
représentation propre octal
hexadécimale pour
afficher un caractère
Unicode, chaque 'n' est
une valeur numérique
\x nn Utilise une Chaque lettre a sa
représentation propre représentation
hexadécimale pour hexadécimale
spécifier un caractère
(nn se compose à
nouveau de deux
chiffres)
\unnnn Utilise la Chaque lettre Unicode
représentation a sa propre
hexadécimale pour représentation
afficher un caractère hexadécimale
Unicode, chaque 'n' est
une valeur numérique
\W Correspond à
n'importe quel mot
non-caractère
\s Correspond à
n'importe quel espace
\S Correspond à tout non-
espace
\d Correspond à toute
valeur décimale
\D Tout caractère saufune
valeur décimale

Directives des pre-processors :


Les directives des pre-processors sont crées comme des messages pour le
compiler, elle sont traités avant chaque compilation. Elles sont signifié par
un symbole dièse (#) et à cause d’eux ne pas être des déclarations ne
nécessitent pas et déclaration de fin de ligne (;).
C# pre-processor directives n’offre rien de différent à ceux dans C++ ou C
et ils ne peuvent pas être utiliser pour les macros

Directive Explication
#define Cela crée un symbole
#undef Utilisé pour un symbole indéfini
#if Cela est utilisé pour tester un
symbole contre une condition
#else Utilisé aux cotés de #if
#elif Et sinon et un si dans la même
déclaration
#endif Utilisé pour signifier une close à un
#if dans la déclaration
#line Modifie le numéro de ligne du
compilateur et une fonctionnalité
facultative consiste à modifier les
sorties de nom de fichier pour les
fichiers et les avertissements
#region Utile pour le formatage
#endregion Montre la fin d’une région

Ci dessus un tableau décemment étoffé qui inclut toutes les directives


principales. Ci dessous sont des exemples de quelques directives utiles

#define & #undef & if


L’exemple ci-dessous montre si #défini une déclaration peut être utilisée
avec une déclaration #if

#define VALUE
using System;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
#if (VALUE)
Console.WriteLine("Defined");
#else
Console.WriteLine("Not Defined");
#endif
Console.ReadKey();
}
}
}

Output
>Defined

Comme vous pouvez le voir ceci peut être utilisé pour basculer facilement
le code, l'exemple le plus courant est l'utilisation du code de débogage ou
d'un mode verbeux.
#define VERBOSE
using System;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Start!");

int a = 1 + 3;
#if (VERBOSE)
Console.WriteLine("Addition complete");
#endif
int b = 1 - 4;
#if (VERBOSE)
Console.WriteLine("Subtraction complete");
#endif

int c = 1 * 3;
#if (VERBOSE)
Console.WriteLine("Multiplication complete");
#endif

int d = 1 / 3;
#if (VERBOSE)
Console.WriteLine("Division complete");
#endif

Console.WriteLine("End!");
Console.ReadKey();
}
}
}

Cet exemple montre un programme basique presque inutile mais il est


supposé pour démontrer comment #define peut être comme des bascules,
copier le et lancer le programme pour les comparer lorsque vous ajoutez ou
enleviez le #define au début.
#if utilise les conditions normales comme une déclaration actuelle, la liste
est ci dessous :
==
|| (OR)
&&
!=
#region
Région n'offre aucun but à un programme lors de l'exécution, mais facilite
le repli et le masquage d'une zone de code, il est utilisé comme ceci:

#region Hide This


Console.WriteLine("Print!");
#endregion
Output
>Print!

Quand cela échoue cela ressemble à sa :

Exception Handing
Une exception est "levée" lorsqu'une erreur se produit, c'est une réponse
une situation à laquelle le programme ne peut pas continuer. Des exceptions
peuvent être gérées cependant et votre programme ne doit pas toujours
exploser, il y a 4 mots-clés; essayer, attraper, finalité et jeter:
try—ceci est utilisé pour entourer le code que vous souhaitez
surveiller pour une exception, si une exception est trouvée cela
transfère le contrôle de la section.
Catch—ceci est le lieu ou le programme finira si une exception
est levée dans une section d’essai d’accompagnement
Finally—ceci peut avvompagner un try/catch mais s'exécutera
toujours indépendamment d'une exception levée, un bon exemple
est lors de l'ouverture d'un fichier à lire, il a toujours besoin de
fermeture.
Throw—ceci est utilisé manuellement pour lever manuellement
une exception avec votre texte customer
Ci dessous un exemple d’utilisation de try/catch :

using System;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
try
{
//Diving by zero error!
int zero = 0;
int i = 1 / zero;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.ReadKey();
}
}
}
Output
> Attempted to divide by zero.

Note : les surlignages signifient que les paramètres pour l’exception, le


texte d'exception peut être obtenu comme ci-dessous avec la propriété
".Message". Mais comme vous pouvez le voir le programme a imprimé le
message d'erreur, mais n'a pas jeté une erreur de compilation, le code dans
l'essai n'a pas été terminé, mais est passé à la zone de capture.
Ici un autre exemple mais cette fois un try/catch/finally est utilisé, ce
programme ouvre un dossier ( assumant qu’il existe) et la déclaration finale
est ici pour être à 100% sure que le dossier est fermé même si une exception
est levée.
using System;
using System.IO;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{

StreamReader sr = null;
try
{
sr = new StreamReader("file.txt");
//Used to simulate an example
throw new Exception("Error reading file!");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
//Closes the file
if (sr != null)
{
sr.Close();
}
}
Console.ReadKey();
}
}
}

Note : l’utilisation de « throw new Exception(… » est utilisé pour lancer


vos propres exceptions, ceci peut être utilisé dans des situations ou vous
avez besoin d’être informer d’une erreur critique de votre programme.
Question de fin de chapitre :

1. Quelles caractéristiques clés une fonction de surcharge


d'opérateur a-t-elle besoin?
2. Quel est le rôle d’une expression régulière ?
3. Quel est le namespace utilisé pour une expression régulière ?
4. Qu’achève le « @ » placé avant la fin d’une ligne ?
5. Comment les directives de C# diffèrent de C ou C++ ?
6. Quand est lancée une déclaration ?
7. Quel est l’usage du mot clé « throw » ?
8. Quel est le rôle de #region et #endregion ?
9. Dans une expression régulière que signifie « ^ » ?
10. Dans une expression régulière que signifierait [abfe]+

Réponses :

1. Publique et statique
2. Utilisé pour correspondre à un motif d’une ligne
3. System.Text.RegularExpressions,
4. Cela dit au compiler de prendre la ligne littéralement et d’ignorer
backslash identifiers.
5. Il n’y a pas de support pour les macros.
6. Toujours, même si une exception est levée.
7. Ceci est utilisé pour créer vos propres exceptions customisées
8. Elles sont utilisées pour formater et améliorer le rendement.
9. Signifie le commencement d’un mot.
10. N’importe nombre de caractères dans une rangée qui sont a,b,f et
e qui correspondrait .
Chapitre 5

Mise en forme de programme

Attribut
Un attribut est une étiquette utilisée pour transmettre au compilateur des
informations sur les comportements des éléments du programme, un attribut
est spécifié par une paire de crochets ([]) et est placé au-dessus de l'élément
sur lequel ils fournissent des informations.
Le cadre .NET fournit deux types d’attributs :
Prédéfinis
Custom built

Prédéfinis
Il y a trois types d’attributs pré-définis :
AttributeUsage
Conditional
Obsolete
Attribute Usage :
L’Attribute Usage décrit comment un attribut custome peut être utiliser et
ou il peut être appliqué, la syntaxe est ci dessous :

[AttributeUsage(validOn, AllowMultiple, Inherited)]


Ou :
validOn spécifie ou l’attibut peut être posé, il utilise
l'énumération "AttributeTargets" qui peut comprendre:
AttributeTargets.Class
AttributeTargets.Constructor
AttributeTargets.Field
AttributeTargets.Method
AttributeTargets.Property

AllowMultiple spécifie si plus d'une version de l'attribut peut être


créée et appliquée.
Inherited spécifie si l'attribut est hérité lorsque les autres classes
héritent de l'attribut auquel la classe est connectée
Ceci est utilisé plus tard pour fabriquer des attributs customisés

Condition
Ces attributs conditionnés sont utilisé pour marquer une méthode qui
dépend d’une certaines directive pre-processor c’est cet exemple que nous
utiliserons pour débugger par exemple :

using System;
using System.Diagnostics;

namespace ConsoleApplication1
{
class Program
{
public static void Main()
{
Debugging();
Console.ReadKey();
}

[Conditional("DEBUG")]
static void Debugging()
{
Console.WriteLine("This is example debugging code:");
Console.WriteLine("Number of loops: " + 1);
Console.WriteLine("Values found: " + 102);
}
}
}

Cela sortira l’exemple d’output si le programme est posé dans le mode


débuggé, cela donne une très bonne façon d'abstraire le code et la sortie
inutile. L'indicateur DEBUG est automatiquement intégré dans Visual
Studio. Par conséquent, lorsque le programme passe en mode de libération,
le mode de débogage est défini sur false et le code ne s'exécute pas.
Ceci peut-être aussi fait avec des directives de pre-processors customisé
comme :

#define CUSTOM
using System;
using System.Diagnostics;

namespace ConsoleApplication1
{
class Program
{
public static void Main()
{
Custom_Method();
Console.ReadKey();
}

[Conditional("CUSTOM")]
static void Custom_Method()
{
Console.WriteLine("Custom output!");
}
}
}

Obsolète :
Ceci est utilisé pour des raisons d'héritage et de compatibilité, si par
exemple vous avez une classe qui a utilisé une fonction SaveFile () mais a
été mise à jour plus tard et cette fonction est devenue obsolète une nouvelle
fonction a été créée appelée Save () () serait marqué comme obsolète, donc
d'autres programmes qui utilisent ces fonctions n'auraient pas de problèmes
de compatibilité.
Cet exemple montre comment utilisé obsolete
using System;

namespace ConsoleApplication1
{
class Program
{
public static void Main()
{
Output old = new Output();
old.PrintData();

Output newV = new Output();


newV.Print();

Console.ReadKey();
}
}

class Output
{
string example = "Example";

[Obsolete("Depreciated! Use Print() instead", false)]


public void PrintData()
{
Console.WriteLine(example);
}
public void Print()
{
Console.WriteLine(example);
}
}
}

Output
>Example
>Example

Comme vous pouvez voir les deux méthodes fonctionnent, cependant le


old.PrintData() vous avertira de cette façon :

Note : en effet, le paramètre 'false' en surbrillance a été utilisé, cela signifie


qu'un simple avertissement est présenté, si cela est vrai une erreur est créée
et ne permettra pas au programme de compiler. Cela apparaîtra dans la liste
des erreurs comme ceci:
Custom Attributes

Le cadre permet aux attributs créés sur mesure de stocker toutes


informations jugées pertinentes par le programmeur, ce qui est très similaire
à la définition d'une classe, mais la classe doit hériter de la classe
System.Attribute, avec l'attribut AttributeUsage défini ci-dessus. Un
exemple de base est ci-dessous, l'exemple est la définition d'un attribut qui
crée simplement une description:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited =


true)]
class Description : Attribute
{
public string Text { get; }

public Description(string text)


{
Text = text;
}
}

Comme vous pouvez le voir cela est très similaire à créer une classe, à
l'exception de l'héritage hors attribut et de l'attribut AttributeUsage ci-
dessus. Cela peut être utilisé comme ça:

[Description("Main method!")]
[Description("AllowMultiple == true, so you can have multiple
Descriptions")]
class Program
{
public static void Main()
{

}
}

Cette information peut être obtenu et utilisé par le processus de


« réflexion » ce qui sera exploré dans la prochaine section.

Réflexion

La réflexion d ‘un objet est utilisé pour obtenir des informations lors de
l’exécution, le System.Reflection donne accès à ces propriétés

Réflexion peut être utilisé :


Voir des informations à propos des attributs
Cela permet un lien tardif aux méthodes et propriétés
Cela permet la création de types lors de l’exécution.

Metadata

Les métadonnées sont des données sur les données, et dans ce cas, il s'agit
de données sur les attributs. Pour commencer, vous devez créer une instance
d'informations sur les membres comme suit:

MemberInfo info = typeof(AttributeTest);

Cela peut être utilisé pour vérifier les informations. L’exemple ci dessous
imprime les attributs attachés

Rappelé vous d’inclure ceci au début


using System.Reflection;

Pour cet exemple, nous allons utiliser le Description Attribute vu plus tôt :

using System;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
AttributeTest t = new AttributeTest();
t.PrintAttributes();
Console.ReadKey();
}
}

[Description("Description 1!")]
[Description("Description 2!")]
class AttributeTest
{
MemberInfo info = typeof(AttributeTest);

public void PrintAttributes()


{
//Returns an array of attributes
object[] attributes = info.GetCustomAttributes(true);

//Prints attributes
foreach (Description attr in attributes)
{
Console.WriteLine(attr.Text);
}
}

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited


= true)]
class Description : Attribute
{
public string Text { get; }

public Description(string text)


{
Text = text;
}
}
}

Output
>Description 1!
>Description 2!

Comme vous pouvez le voir le programme a sorti le texte de description des


attributs qui y sont attachés. La ligne:

…info.GetCustomAttributes(true);

Renvoie la liste des attributs et les attributs sont ensuite imprimés dans la
boucle foreach suivante.

Indexers

Les indexers permettent aux classes cutstomisées d’être indexé presque


comme dans un étalage, chaque membre est accédé avec un étalage
opérateur accès ([]).
L’indexer est défini comme :
type this[int index]
{
get
{
//returns values
}
set
{
//sets values
}
}

Ou vous pouvez l’appelez comme ceci

Example[2];
Avec la même exacte syntaxe sur l’étalage

Donc pour cet exemple il s'agira d'un chercheur d'inventaire en magasin,


l'indexeur prendra un nom et recherchera le catalogue:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
class Program
{
static void Main()
{
Inventory main_floor = new Inventory();

//Adds Items
main_floor.AddItem(new Item("PS4", 499.50));
main_floor.AddItem(new Item("RX_480", 200.50));

//Uses indexer to grab price


Console.WriteLine("Price: " + main_floor["RX_480"]);
Console.ReadKey();
}
}

class Inventory
{
List<Item> Items = new List<Item>();

public void AddItem(Item item)


{
Items.Add(item);
}

public double this[string index]


{
get
{
foreach (Item item in Items)
{
if (item.Name == index)
{
return item.Price;
}
}

//Used to signify that there is not item


return -1;
}
set
{
//You can also use this to set a value much like setting a value in
//an attribute
}

}
}

//Simple class to hold item


class Item
{
public Item(string name, double price)
{
Name = name;
Price = price;
}

public string Name { get; }


public double Price { get; }
}
}

Les deux zones surlignées signifient ou l’indexer est défini et utilisé. Le


programme garde juste les traces des items et l ‘indexer est utilisé pour
prendre une ligne pour trouver le prix.

Exercice
Ajoutez une version surchargée de l’indexer (ceci eut être fait) qui prend le
prix comme index et renvoie le nom. Pour des raisons de simplicité, ne vous
inquiétez pas si deux articles ont le même prix, mais supposez que tous les
articles ont des prix différents

Solution

Votre classe d’inventaire devrait ressembler à ceci : ( ce nouvel indexer est


surligné)
class Inventory
{
List<Item> Items = new List<Item>();

public void AddItem(Item item)


{
Items.Add(item);
}

public double this[string index]


{
get
{
foreach (Item item in Items)
{
if (item.Name == index)
{
return item.Price;
}
}

return -1;
}
}
public string this[double index]
{
get
{
foreach (Item item in Items)
{
if (item.Price == index)
{
return item.Name;
}
}

return null;
}
}
}

Collections

Les classes collections sont spécialement construites dans les classes


utilisées pour le stockage et la récupération de données. Certaines de ces
classes possèdent des membres qui sont définis comme « objet », l’objet
est la classe de base pour toutes les données types dans C#. Ceci était la
méthode de stockage de n’importe quel type de données avant que le
concept de classes génériques a été implanté.

Ci dessous une liste et des explications de la collection principale :

List<T>
List est la version de la mise à jour plus moderne de l’ArrayList, c'est une
liste de taille dynamique qui est utilisée pour stocker différentes valeurs du
même type, elle peut être étendue et réduite (où elle se redimensionne
automatiquement). La classe List est une classe générique (apprise dans le
chapitre suivant) mais ce que cela signifie dans ce cas, c'est qu'elle peut
contenir n'importe quoi, même d'autres listes (Voici comment vous pouvez
faire une liste 2D).

Une liste est définie comme ceci :

List<type> list = new List<type>();

Ou par exemple une liste d’integrers est défini comme :

List<int> list = new List<int>();

Les valeurs peuvent être ajouté à la liste en utilisant la fonction l’.Add() et


peut être enlevé en utilisant .Remove()

Vous pouvez obtenir la longueur de la Liste <> ou beaucoup d’items il se


loge en accédant à la propriété .Count.

Hashtable

Note : ceci est déprécié et ne devrait pas être utilisé, vous devriez utilisé un
Dictionnaire <>, mais c’est important que vous sachiez comment la
collectionne fonctionne.

Une hashtable est une table (comme son nom l'indique) qui stocke des
paires clé-valeur, ces paires sont déterminées par une fonction de hachage.
Une fonction de hachage prend une entrée de n'importe quelle longueur et
renvoie une valeur de longueur fixe, ce processus ne peut pas non plus être
annulé. Donc, dans le cas des tables de hachage, une paire de clés à ajouter
est hachée, maintenant ce hachage sera égal à une position dans la table. La
paire de clés sera ensuite stockée à cet emplacement.

Note : la clé spécifiée doit être unique

L'une des plus grandes positivités d'une table de hachage est la rapidité
d'accès ou de vérification de la table et des éléments, car dans la plupart des
structures linéaires comme un tableau ou une liste, vous devez rechercher
une liste de façon exhaustive un objet, mais dans le cas d'une hashtable si
une cible de recherche a haché pour trouver où elle irait et qu'il n'y a pas de
valeur à cet endroit, elle n'est pas là.

Dictionary <TKey ,TValue>

Il doit être comme la List<T>, le Dictionnaire est un type générique de


données qui est basé sur le Hashtable mentionné précédemment est utilisé
comme une valeur de clé paire pour sauvegarder les données.

Un dictionnaire est défini comme :

Dictionary<KeyType, ValueType> dictionary = new Dictionary<KeyType,


ValueType>();

Ou « Key/Type » et « ValueType » les deux définies comme le type de


données qui seront utilisé pour stocker chaque membre de la paire.

Ajoutant au dictionnaire peut être fait ainsi


dictionary.Add(1, "Value");

Et vous pouvez obtenir une valeur cherchant une clé :

Console.WriteLine(dictionary[key]);

Et les valeurs peuvent être incrémentées en utilisant la valeur foreach, le


type qui contient les deux valeurs est appelé KeyValuePair <TKey,
TValue>. C'est effectué de cette manière

foreach (KeyValuePair<int,string> item in dictionary)


{
Console.WriteLine(item.Key);
Console.WriteLine(item.Value);
}

Stack

Ceci est connu comme une structure de données du premier entré, dernier
sorti (FILO) où lorsqu'une valeur est placée dans son 'push' et qu'une valeur
est prise (ne peut être que du haut de la pile), elle est sautée.

Un stack est défini comme :

Stack s = new Stack();

Les valeurs sont ajoutées en poussant


s.Push(2);

Et pris de par éclater. Notez l'utilisation de la distribution entière, car les


éléments sont stockés en tant qu'objets.

int value = (int)s.Pop();

Queue

Une file d'attente est très similaire à une pile mais est une structure de
données First-in First-out (FIFO). Les éléments sont ajoutés et supprimés en
utilisant 'Enqueue ()' et 'Dequeue ()' respectivement.

Une file d'attente est définie comme suit:

Queue q = new Queue();

Et l'ajout d'une suppression d'une file d'attente est fait comme suit:

//Add to the queue


q.Enqueue(1);

//Take from the queue


int i = (int)q.Dequeue();
Genericques

Un générique est une immense fonctionnalité de C# qui permet au


programmer de créer une seule définition de classe qui prend n’importe
quel type de données, même les classes customisés soit même. L’usage du
type générique est dénoté par « T », depuis ces origines cette tige est
originellement appelé « Templating » dans C++. Par exemple la Liste<>
collection nous avons rencontré précédemment est une classe générique,

Vous pouvez créer une classe générique comme ceci :

class Generic<T>
{

Remarquez les utilisation de <>, ceux-ci sont utilisés pour créer un type de
données générique, ceux-ci n'ont pas besoin d'être définis comme 'T' et
peuvent être des définitions multiples:

class Generic<Example, AnotherExample>


{

L’exemple ci dessus est valide mais est conseillé pour la lisibilité pour
commencer la défintion avec un « T ». Ci dessous un exemple comment
utiliser le type de données générique

class Generic<TEx>
{
public TEx value;

public Generic(TEx _value)


{
value = _value;
}

public void Print()


{
Console.WriteLine($"Data is: {value}", value);
}
}

La définition de la classe peut être utilisé avec n’importe quel type de


données définis :

Generic<string> gStr = new Generic<string>("Hello");


gStr.Print();

Generic<int> gInt = new Generic<int>(2);


gInt.Print();
Comme vous pouvez le voir le fragment de code ci dessus défini le type à
utiliser par définition dans le « <> ».Dans cet exemple ci dessous vous
verrez qu’il fonctionne avec un type d’utilisateur défini :

Generic<myClass> gMyClass = new Generic<myClass>(new myClass());


gMyClass.Print();

Avec une output de :

> Data is: ConsoleApplication1.myClass

Ainsi les génériques vous permettent d’une façon très dynamique de définit
une classe ce qui permet presque une quantité infinie de données types. Ci
dessous un actuel programme qui est utilisé pour échanger les deux types de
données

using System;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
int a = 10;
int b = 42;

Console.WriteLine($"a is before swap: {a}", a);


Console.WriteLine($"b is before swap: {b}", b);

Swap<int> swap = new Swap<int>(ref a, ref b);

Console.WriteLine($"a is after swap: {a}", a);


Console.WriteLine($"b is after swap: {b}", b);

Console.ReadKey();
}
}
public class Swap<T>
{
public Swap(ref T Left, ref T Right)
{
T temp;
temp = Left;
Left = Right;
Right = temp;
}
}
}

Un autre exemple pourrait être de un créer un étalage générique, noté


l’utilisation de l’indexer pour rendre accessible et modifier les valeurs plus
facilement.
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
Array<int> intArray = new Array<int>(1);
intArray[0] = 1;

Array<string> strArray = new Array<string>(1);


strArray[0] = "Hello";

Console.WriteLine(intArray[0]);
Console.WriteLine(strArray[0]);
Console.ReadKey();
}
}
public class Array<T>
{
T[] array;
public Array(int size)
{
array = new T[size];
}

//Indexer used to access and change values


public T this[int index]
{
get
{
return array[index];
}
set
{
array[index] = value;
}
}

}
}
C’est un peu de la triche d’avoir un étalage interne défini mais vous
obtiendrez l’image. L’étalage défini comme un étalage de générique, ce qui
vous permet de définir un type plus tard.

Quiz de fin de chapitre :


1. Quels sont les deux types d ‘attributs que le .NET Framework
supporte ?
2. Ou trouverez vous normalement la version Obselete dans
l’attribut ?
3. Lorsque vous créez un attribut customisé, quelle classe a besoin
d’en hériter ?
4. Comment définiriez vous les « metadata » ?
5. Quel est le rôle de réflexion dans le code ?
6. Quelle méthode peut être utilisée pour obtenir les attributs dans
une fonction ?
7. Quelle est la raison la plus importante d’utiliser un indexer ?
8. Que réfère un stack et que fait FIFO ?
9. Quelle parenthèse signifie une classe générique ?
10. Quelle variable est utilisée pour sauvegarder la clé et la valeur
d’un dictionnaire ?
Réponses
1. Prédéfinis et custom built
2. Sur une ancienne méthode obsolète qui ne peut pas être supprimée
pour des raisons de compatibilité mais qui doit être éliminée
progressivement.
3. System.Attribute
4. Données à propos des données
5. Voir les données sous-jacente de fonction ou de propriéts
6. GetCustomAttributes
7. Améliorer la syntaxe lorsque vous accédez ou modifiez les valeurs
dans la classe
8. First in first out
9. <and> , dans les parenthèses des types génériques sont définis
10. KeyValuePair<TKey, TValue>
Chapitre 6

Processus et fonctionnalité

Délégués
Les Délégués sont très similaire à la fonction de pointeur dans C ou C++ si
vous avez déjà croisé ce concept auparavant. Ainsi les délégués sont une
variable de type référence qui contient des références à une fonction.

Un réel usage pour les délégués est l’utilisation pour les rappelles
dynamiques d’une fonction, le délégué est passé comme un paramètre et la
fonction est appelée dynamiquement.
Par exemple la définition ci dessous peut être utilisé pour référencer
n’importe quel méthode qui possède deux paramètres internes, il retourne et
est marqué comme privé.
public delegate int ExampleDeligate(int a, int b);

Ensuite vous devriez créer une instance de ce délégué en utilisant le


« nouveau » mot clé comme ci dessous
using System;
namespace ConsoleApplication1
{
class Program
{
public delegate int ExampleDeligate(int a, int b);
static void Main()
{
ExampleDeligate addDel = new
ExampleDeligate(AddTwoNumbers);
}

public static int AddTwoNumbers(int a, int b)


{
return a + b;
}
}
}

Comme vous pouvez le voir le délégué est initialisé et dans les parenthèses
il y a le nom de la fonction de référence.

Pour utiliser le délégué juste traiter le comme n’importe quel fonction.

addDel(1, 2);

Cela vous vous donne une bonne dynamique, une façon utilisable pour
passer les fonctions comme des paramètres. Ci dessous un exemple utilisant
cet acte comme un calculateur :

using System;
namespace ConsoleApplication1
{
class Program
{
public delegate float Calculation(float a, float b);
static void Main()
{
//All you have to do is pass in the function by name
Calculater(10, 20, Add);
Calculater(5, 267, Sub);
Calculater(14, 2, Mul);
Calculater(10, 10, Div);

Console.ReadKey();
}

public static void Calculater(float a, float b, Calculation cal)


{
//Dynamic method call
float value = cal(a, b);
Console.WriteLine($"New value is: {value}", value);
}

//Basic functions
public static float Add(float a, float b)
{
return a + b;
}
public static float Sub(float a, float b)
{
return a - b;
}
public static float Mul(float a, float b)
{
return a * b;
}
public static float Div(float a, float b)
{
return a / b;
}
}
}

Output
>New value is: 30
>New value is: -262
>New value is: 28
>New value is: 1

Les zones surlignées montrent comment vous pouvez passer un délégué en


un paramètre et tout ce que vous faites est de passer la fonction dans les
paramètres de la position de délégués, ce qui donne une magnifique
dynamique et une simple manière de lancer le code.

Multicasting

Les délégués permettent aussi l’enchainement de fonction appelé l’une et


l’autre
Calculation DEL = new Calculation(Add);
DEL += new Calculation(Sub);
DEL += new Calculation(Mul);
DEL += new Calculation(Div);

Ce qui signifie que toutes les méthodes seront appelées en une longue
chaine, donc par exemple disons que les paramètres sont 10 et 20 la
réponse serait égale à la dernière méthode ajoutée, dans ce cas ( 10/20=0.5)
dans cet exemple cela lance toutes les méthodes mais elles ne s’affectent
pas les unes les autres donc cela ne change pas la réponse, donc faites
attention à la considération nécessaire lorsque vous choisissez quelle
méthode ajouter à un multicast délégué.

Mais les nouveaux exemples ci dessous devraient multicasting quand vous


ne retourniez pas les valeurs
using System;
namespace ConsoleApplication1
{
class Program
{
public delegate void Print();
static void Main()
{
Print call = new Print(PrintHello);
call += new Print(PrintToday);
call += new Print(PrintCar);

//Method call
call();

Console.ReadKey();
}

public static void PrintHello()


{
Console.WriteLine("Hello");
}
public static void PrintToday()
{
Console.WriteLine("Today");
}
public static void PrintCar()
{
Console.WriteLine("Car");
}
}
}

Ceci montre que vous pouvez manipulez de multiples fonction appelées en


un seul délégué, cela peut être aussi passé comme un paramètre et utilisé
dans une autre fonction.

Méthode anonyme

Précédemment nous avons mentionné que les délégués sont utilisés pour
référencer n’importe quelle méthode avec la même signature que le
délégué.

Les méthodes déléguées fournissent une technique pour passer un code de


blocage comme un paramètre délégué. Ce sont des méthodes sans noms,
donc il y a juste un corps. Vous n’avez pas besoin de définir le type de
retour de la méthode, il est inféré (déterminé automatiquement) à partir de
l'instruction return dans le corps des méthodes.
Il y a effectivement des délégués qui ne se référencent pas à la méthode
actuelle, cela est juste créer pour le délégué, donc revenons à notre exemple
calculateur qui ressemblerait à ceci :

using System;
namespace ConsoleApplication1
{
//Delegate
public delegate int Calculation(int a, int b);

class Program
{
Calculation add = delegate (int a, int b)
{
return a + b;
};
Calculation sub = delegate (int a, int b)
{
return a - b;
};
Calculation mul = delegate (int a, int b)
{
return a * b;
};
Calculation div = delegate (int a, int b)
{
return a / b;
};
static void Main()
{
Program p = new Program();

p.add(10, 20);

p.div(2, 10);

Console.WriteLine();
}
}
}

Où chaque commande est définie comme une méthode anon, et juste


appelée comme une fonction régulière.

L’utilisation de méthodes anonymes réduit la surcharge de codage de


créations de délégués car d’autres méthodes n’ont pas besoin de définir les
prior pour créer une instance de délégué.

La méthode semble inutile.

Donc, les méthodes anonymes doivent être utilisées lorsque les frais
généraux de création d'un

Evènements
Les événement sont une action de l’utilisateur comme entré, un click, un
mouvements de la sourie etc... Ceci permet au programme ou au code
d’exécuter ce qui est dépendant d’un événement déclencheur (trigger
détection)
Les délégués sont souvent utilisés avec des évènements qui sont associés
avec le gestionnaire d'événements (détection de déclencheur) en utilisant le
délégué. Les évènements utilisent les publisher-subscriber modèle :

Un publisher est une classe qui contient l’événement, comme le


nom le suggère utilisé pour publier l’évènement.
La classe subscriber est une classe qui accepte l’événement. Le
délégué dans la classe du publisher implique la méthode de la
classe du subscriber
Déclarer un événement

Pour déclarer un événement dans une classe, vous aurez besoin


premièrement d’un type de délégué défini et le joindre au handler. Le code
ci dessous démontre ceci :

using System;
namespace ConsoleApplication1
{
//Delegate
public delegate string DelExample(string str);

class EventExample
{
//Event decleration
event DelExample MyEvent;

public EventExample()
{
MyEvent += new DelExample(PrintWelcome);
}

public string PrintWelcome(string username)


{
return username + " Welcome!";
}
static void Main()
{
EventExample ex = new EventExample();

//Calls the event handler


Console.WriteLine(ex.MyEvent("User1"));
Console.ReadKey();
}
}
}

Multithreading

Un fil est un seul processus d’exécution, le multithreading est la capacité


de lancer plusieurs petits processus au même moment, cela arrête le
programme de gâcher des cycles CPU en attente et peut rendre les
programmes beaucoup plus efficace.

Cependant, introduire le multithreading dans des problèmes qui sont


triviaux ou ne peuvent résolus en même temps peut réduire l’efficacité d’un
programme.
Jusqu’à maintenant nous avons écris des programmes qui s’exécutent en un
fil et que l’ordinateur exécute du début à la fin en une fois.`

Threads

Les outils requis pour créer et travailler avec les restes de fils dans le
System.Threading classe. Une des fonctions les plus simples est d’être
capable d’attraper le fil en cour de cette manière :

Thread t = Thread.CurrentThread;

Créer un fil

Vous pouvez créer une ligne de cette façon :

Thread s = new Thread(DoLotsOfWork);

Avec la fonction la ligne exécutée sera contenue dans les parenthèses.


L’exemple ci dessous montre comment ce comportement simultané peut
fonctionner :

using System;
using System.Threading;

namespace ConsoleApplication1
{
class Program
{
public static void DoLotsOfWork()
{
for (int i = 0; i < 5; i++)
{
Thread t = Thread.CurrentThread;
Console.WriteLine($"{t.Name}: i is equal to: {i}");
}
}

static void Main()


{
for (int i = 0; i < 5; i++)
{
//Creates a thread
Thread s = new Thread(DoLotsOfWork);

//Assigns the thread a name


s.Name = $"Thread {i}";

s.Start();
}

Console.ReadKey();
}
}
}
Output

>Thread 2: i is equal to: 0

>Thread 2: i is equal to: 1

>Thread 2: i is equal to: 2

>Thread 2: i is equal to: 3

>Thread 2: i is equal to: 4

>Thread 0: i is equal to: 0

>Thread 1: i is equal to: 0

>Thread 0: i is equal to: 1

>Thread 1: i is equal to: 1

>Thread 1: i is equal to: 2

>Thread 1: i is equal to: 3


>Thread 1: i is equal to: 4

>Thread 0: i is equal to: 2

>Thread 0: i is equal to: 3


>Thread 0: i is equal to: 4

>Thread 3: i is equal to: 0


>Thread 3: i is equal to: 1

>Thread 3: i is equal to: 2


>Thread 3: i is equal to: 3

>Thread 3: i is equal to: 4


>Thread 4: i is equal to: 0

>Thread 4: i is equal to: 1

>Thread 4: i is equal to: 2


>Thread 4: i is equal to: 3

>Thread 4: i is equal to: 4


Note : pour vous cela pourrait sortir dans un ordre différent.

Cet exemple ci dessus crée 5 fils qui sortent 5 itérations d'une boucle for,
comme vous pouvez le voir tout ne sort pas en ordre, cela est du au fait que
tout s’opère en même temps et que chaque ligne travaille indépendamment.

Ce manque d’ordre peut être un problème dans certaines circonstances,


c’est la ou le mot clé « lock » vient de son propre usage, il est utilisé pour
entourer le code qui est jugé crucial et le code qui ne peut pas avoir
plusieurs threads en utilisant en même temps, nous allons adapter l'exemple
d'avant pour inclure le verrou:

using System;
using System.Threading;

namespace ConsoleApplication1
{
class Program
{
static object padLock = new object();
public static void DoLotsOfWork()
{
lock (padLock)
{
for (int i = 0; i < 5; i++)
{

Thread t = Thread.CurrentThread;
Console.WriteLine($"{t.Name}: i is equal to: {i}");
}
}
}

static void Main()


{
for (int i = 0; i < 5; i++)
{
//Creates a thread
Thread s = new Thread(DoLotsOfWork);

//Assigns the thread a name


s.Name = $"Thread {i}";

s.Start();
}

Console.ReadKey();
}
}
}

Output
>Thread 0: i is equal to: 0

>Thread 0: i is equal to: 1

>Thread 0: i is equal to: 2


>Thread 0: i is equal to: 3

>Thread 0: i is equal to: 4

>Thread 2: i is equal to: 0


>Thread 2: i is equal to: 1

>Thread 2: i is equal to: 2

>Thread 2: i is equal to: 3


>Thread 2: i is equal to: 4

>Thread 1: i is equal to: 0

>Thread 1: i is equal to: 1


>Thread 1: i is equal to: 2

>Thread 1: i is equal to: 3

>Thread 1: i is equal to: 4


>Thread 3: i is equal to: 0

>Thread 3: i is equal to: 1


>Thread 3: i is equal to: 2

>Thread 3: i is equal to: 3

>Thread 3: i is equal to: 4

>Thread 4: i is equal to: 0

>Thread 4: i is equal to: 1

>Thread 4: i is equal to: 2

>Thread 4: i is equal to: 3

>Thread 4: i is equal to: 4

Comme vous pouvez le voir chaque itération de boucle sort dans l’ordre de
0 à 4, on pourrait croire que les lignes ne sortent pas dans l’ordre, le mot
lock travaille sur un premier arrivé premier servi de base et une fois qu'un
fil le touche, il devient verrouillé jusqu'à ce que l'objet soit libéré. S'il vous
plaît également pas l'utilisation d'un objet à côté de la serrure, cela est
utilisé comme un drapeau pour si le verrou est disponible ou verrouillé.

Ce système de verrouillage est très utile quand il s'agit de traiter des


fichiers, si deux threads devaient essayer de lire ou écrire dans un fichier en
même temps, il y aurait des erreurs ou des lignes n'apparaîtraient pas dans
l'ordre. Voici un exemple illustrant ceci:
using System;
using System.IO;
using System.Threading;

namespace ConsoleApplication1
{
class Program
{
public static void WriteToFile()
{
//Error here!
StreamWriter sw = new StreamWriter("file.txt");
for (int i = 0; i < 5; i++)
{
sw.WriteLine($"Test {i}");
}
sw.Close();
}

static void Main()


{
for (int i = 0; i < 5; i++)
{
//Creates a thread
Thread s = new Thread(WriteToFile);

//Assigns the thread a name


s.Name = $"Thread {i}";
s.Start();
}

Console.ReadKey();
}
}
}

Cela va planter et lancer une exception System.IO.IOException lorsque


deux threads ou plus essaieront d'ouvrir le fichier pour y écrire en même
temps. Ceci est un usage du monde réel pour la structure du verrou, car
l'ajout d'un verrou résoudra ceci, ci-dessous est le verrou introduit, cela
résoudra le problème:

using System;
using System.IO;
using System.Threading;

namespace ConsoleApplication1
{
class Program
{
static object padLock = new object();
public static void WriteToFile()
{
lock (padLock)
{
StreamWriter sw = new StreamWriter("file.txt");
for (int i = 0; i < 5; i++)
{
sw.WriteLine($"Test {i}");
}
sw.Close();
Console.WriteLine("File written to!");
}
}

static void Main()


{
for (int i = 0; i < 5; i++)
{
//Creates a thread
Thread s = new Thread(WriteToFile);

//Assigns the thread a name


s.Name = $"Thread {i}";

s.Start();
}

Console.ReadKey();
}
}
}
Ce code ne crashera pas mais il ne peut être considéré comme
multithreated, il utilise plusieurs threads mais joue comme une application
à une thread, la déclaration verrouillage ne devrait être utilisé seulement
lorsque c’est nécessaire. Copiez ce code et lancez le pour vous familiarisez
avec son fonctionnement.

LINQ

LINQ signifie Langage Integrated Query et résout les problèmes avec des
données d’interrogation et permet une syntaxe stricte, lisible et compacte
pour le retour des données d’interrogation.

Nous couvrirons seulement le LINQ queries pour les objets internes, mais
LINQ peut-être utilisé pour questionner les données en différentes façons.
Les différentes façons sont :

LINQ aux objets


LINQ à XML
LINQ à des ensembles de données
LINQ à SQL (DLINQ)
LINQ à des entités

Il y a deux types de syntaxes pour LINQ :

Lambda (Method) Syntax


var longWords = words.Where(w => w.Length > 10);
Query (Compression) Syntax
var longWords = from w in words where w.Length > 10 select w;

Nous verrons seulement la syntaxe query car je pense que c’est la plus
simple à utiliser mais soyez libre de jeter un coup d’œil à l’autre query pour
des recherches en plus.

Query syntaxe :

La syntaxe query est juste une représentation comparable à celle de SQL,


avec un SELECT, FROM et WHERE représenté de manières un peu
différentes. Pour utiliser LINQ queries, vous aurez besoin d’inclure
System.linq. Ci dessous un exemple d’utilisation de LINQ pour chercher à
travers quelque ligne pour des valeurs avec moins de cinq lettres :
using System;
using System.Linq;

namespace ConsoleApplication1
{
class Program
{
static void Main()
{
string[] words = {"test","verylongword", "sw", "one"};

var shortWords = from word in words


where word.Length < 5
select word;

foreach (var word in shortWords)


{
Console.WriteLine(word);
}
Console.ReadKey();
}
}
}

Output
>test
>sw
>one

La déclaration LINQ est surlignée et sera cassé :

from word in words


Cela définit la gamme et d’ou vient elle, c'est effectivement dire chaque mot
dans le tableau de la chaîne «mots»

where word.Length < 5

En utilisant la gamme de valeur des mots , cela attache une propriété et la


compare à une valeur, c'est une condition où si une valeur correspond à
"vrai" sera ajouté à la sortie.
select word;
Si la précédente relation était vraie, c'est la valeur à prendre, donc par
exemple vous pouvez retourner la longueur de tous les mots sous 5 valeurs
en disant à la fin de la requête:

select word.Length;

Exercice
Dans le squelette du programme ci dessous ajoutez une déclaration LINQ
pour chercher un étalage de valeur de « nombres » pour chercher ces
mêmes nombres. Ensuite utilisez une boucle foreach pour sortir le résultat.

Code

using System;
using System.Linq;

namespace ConsoleApplication1
{
class Program
{
static void Main()
{
int[] numbers = {1, 4, 99, 34, 23, 12, 3, 2, 909, 1000, 13, 1, 2};

//Add code goes here


Console.ReadKey();

}
}
}

Solution

using System;
using System.Linq;

namespace ConsoleApplication1
{
class Program
{
static void Main()
{
int[] numbers = {1,4,99, 34, 23, 12, 3, 2, 909, 1000, 13, 1, 2};

var evenNumbers = from value in numbers


where value % 2 == 0
select value;

foreach (var value in evenNumbers)


{
Console.WriteLine(value);
}
Console.ReadKey();
}
}
}

The output should also be:

>4

>34

>12

>2

>1000

>2

Donc rappelez vous que LINQ offre une syntaxe très simple et contrôlé
pour rechercher des données, il peut aussi être utilisé pour rechercher à
travers de multiples types de données incluant les commandes de recherche
SQL sur une base de donnée pour les rassembler dans un tableau qui peut
être incroyablement puissant pour un programmeur.
Quiz de fin de chapitre :
1. Qu’est ce qu’un délégué permet au programmeur de faire ?
2. Qu‘est ce que le multicasting vous permet de faire avec le
délégué ?
3. Qu’est ce qu’une méthode anonyme ?
4. A quoi correspond un gestionnaire d’évènements ?
5. Qu’est ce qu’un thread ?
6. Quel est le nom de la structure qui prévient deux threads
d’utiliser le même block de code ?
7. Que signifie LINQ ?
8. Qu’est ce LINQ vous permet de faire ?
9. Qu’elles sont les deux types de syntaxes de LINQ ?
10. Dans quel scénario le multithreadong devrait maintenant vous
aidez ?

Réponses
1. Sauvegarder une référence pour une fonction, ce qui permettra au
programmer de faire passer les appels de fonction en tant que
paramètre.
2. Vous pouvez écrasez plusieurs fonctions d’appels en un seul
délégué.
3. Une fonction sans définition de fonction est juste un délégué
définis avec un corps
4. Un délégué qui se déclenche lorsque l’événement est déclenché
5. Un seul procédé indépendant d’exécution
6. Verrou
7. Language Integrated Query
8. Une recherche de données rapides pour des résultats, par
exemple si vous voulez travaillez avec une longueur de cinq
caractères
9. Query et Lambda
10. Lorsque le problème est trivial i.e un simple problème.

You might also like